forked from TrueCloudLab/frostfs-s3-gw
[#428] Update SDK
Includes: - container removal fix - new session token structure: authmate does not parse session context anymore, instead it is application defined flexible structure with container ID encoded in human-readable format Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
parent
9d3e6f75be
commit
1c33f06bfe
17 changed files with 184 additions and 151 deletions
|
@ -210,7 +210,7 @@ func (h *handler) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) updateBucketACL(r *http.Request, astChild *ast, bktInfo *data.BucketInfo, sessionToken *session.Token) error {
|
func (h *handler) updateBucketACL(r *http.Request, astChild *ast, bktInfo *data.BucketInfo, sessionToken *session.Container) error {
|
||||||
bucketACL, err := h.obj.GetBucketACL(r.Context(), bktInfo)
|
bucketACL, err := h.obj.GetBucketACL(r.Context(), bktInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not get bucket eacl: %w", err)
|
return fmt.Errorf("could not get bucket eacl: %w", err)
|
||||||
|
|
|
@ -346,7 +346,7 @@ func (h *handler) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
sessionTokenSetEACL *session.Token
|
sessionTokenSetEACL *session.Container
|
||||||
|
|
||||||
uploadID = r.URL.Query().Get(uploadIDHeaderName)
|
uploadID = r.URL.Query().Get(uploadIDHeaderName)
|
||||||
uploadInfo = &layer.UploadInfoParams{
|
uploadInfo = &layer.UploadInfoParams{
|
||||||
|
|
|
@ -176,7 +176,7 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
newEaclTable *eacl.Table
|
newEaclTable *eacl.Table
|
||||||
sessionTokenEACL *session.Token
|
sessionTokenEACL *session.Container
|
||||||
containsACL = containsACLHeaders(r)
|
containsACL = containsACLHeaders(r)
|
||||||
reqInfo = api.GetReqInfo(r.Context())
|
reqInfo = api.GetReqInfo(r.Context())
|
||||||
)
|
)
|
||||||
|
@ -286,7 +286,7 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
newEaclTable *eacl.Table
|
newEaclTable *eacl.Table
|
||||||
tagSet map[string]string
|
tagSet map[string]string
|
||||||
sessionTokenEACL *session.Token
|
sessionTokenEACL *session.Container
|
||||||
reqInfo = api.GetReqInfo(r.Context())
|
reqInfo = api.GetReqInfo(r.Context())
|
||||||
metadata = make(map[string]string)
|
metadata = make(map[string]string)
|
||||||
containsACL = containsACLHeaders(r)
|
containsACL = containsACLHeaders(r)
|
||||||
|
|
|
@ -82,7 +82,7 @@ func parseRange(s string) (*layer.RangeParams, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSessionTokenSetEACL(ctx context.Context) (*session.Token, error) {
|
func getSessionTokenSetEACL(ctx context.Context) (*session.Container, error) {
|
||||||
boxData, err := layer.GetBoxData(ctx)
|
boxData, err := layer.GetBoxData(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -187,7 +187,7 @@ func (n *layer) GetContainerEACL(ctx context.Context, idCnr *cid.ID) (*eacl.Tabl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) deleteContainer(ctx context.Context, idCnr *cid.ID) error {
|
func (n *layer) deleteContainer(ctx context.Context, idCnr *cid.ID) error {
|
||||||
var sessionToken *session.Token
|
var sessionToken *session.Container
|
||||||
boxData, err := GetBoxData(ctx)
|
boxData, err := GetBoxData(ctx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
sessionToken = boxData.Gate.SessionTokenForDelete()
|
sessionToken = boxData.Gate.SessionTokenForDelete()
|
||||||
|
|
|
@ -138,7 +138,7 @@ type (
|
||||||
ACL uint32
|
ACL uint32
|
||||||
Policy *netmap.PlacementPolicy
|
Policy *netmap.PlacementPolicy
|
||||||
EACL *eacl.Table
|
EACL *eacl.Table
|
||||||
SessionToken *session.Token
|
SessionToken *session.Container
|
||||||
LocationConstraint string
|
LocationConstraint string
|
||||||
ObjectLockEnabled bool
|
ObjectLockEnabled bool
|
||||||
}
|
}
|
||||||
|
@ -627,7 +627,7 @@ func (n *layer) CreateBucket(ctx context.Context, p *CreateBucketParams) (*data.
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.SessionToken != nil && bktInfo.Owner.Equals(*p.SessionToken.OwnerID()) {
|
if p.SessionToken != nil && p.SessionToken.IssuedBy(*bktInfo.Owner) {
|
||||||
return nil, errors.GetAPIError(errors.ErrBucketAlreadyOwnedByYou)
|
return nil, errors.GetAPIError(errors.ErrBucketAlreadyOwnedByYou)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ type PrmContainerCreate struct {
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Token of the container's creation session. Nil means session absence.
|
// Token of the container's creation session. Nil means session absence.
|
||||||
SessionToken *session.Token
|
SessionToken *session.Container
|
||||||
|
|
||||||
// Basic ACL of the container.
|
// Basic ACL of the container.
|
||||||
BasicACL acl.BasicACL
|
BasicACL acl.BasicACL
|
||||||
|
@ -176,7 +176,7 @@ type NeoFS interface {
|
||||||
// Successful return does not guarantee actual removal.
|
// Successful return does not guarantee actual removal.
|
||||||
//
|
//
|
||||||
// It returns any error encountered which prevented the removal request from being sent.
|
// It returns any error encountered which prevented the removal request from being sent.
|
||||||
DeleteContainer(context.Context, cid.ID, *session.Token) error
|
DeleteContainer(context.Context, cid.ID, *session.Container) error
|
||||||
|
|
||||||
// SelectObjects performs object selection from the NeoFS container according
|
// SelectObjects performs object selection from the NeoFS container according
|
||||||
// to the specified parameters. It selects user's objects only.
|
// to the specified parameters. It selects user's objects only.
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/creds/tokens"
|
"github.com/nspcc-dev/neofs-s3-gw/creds/tokens"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/object/address"
|
"github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
|
@ -352,48 +353,6 @@ func restrictedRecords() (records []*eacl.Record) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildContext(rules []byte) ([]*session.ContainerContext, error) {
|
|
||||||
var sessionCtxs []*session.ContainerContext
|
|
||||||
|
|
||||||
if len(rules) != 0 {
|
|
||||||
// cast ToV2 temporary, because there is no method for unmarshalling in ContainerContext in api-go
|
|
||||||
err := json.Unmarshal(rules, &sessionCtxs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to unmarshal rules for session token: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
containsPut = false
|
|
||||||
containsSetEACL = false
|
|
||||||
)
|
|
||||||
for _, s := range sessionCtxs {
|
|
||||||
if s.IsForPut() {
|
|
||||||
containsPut = true
|
|
||||||
} else if s.IsForSetEACL() {
|
|
||||||
containsSetEACL = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if containsPut && !containsSetEACL {
|
|
||||||
ectx := session.NewContainerContext()
|
|
||||||
ectx.ForSetEACL()
|
|
||||||
sessionCtxs = append(sessionCtxs, ectx)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sessionCtxs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
sessionCtxPut := session.NewContainerContext()
|
|
||||||
sessionCtxPut.ForPut()
|
|
||||||
|
|
||||||
sessionCtxDelete := session.NewContainerContext()
|
|
||||||
sessionCtxDelete.ForDelete()
|
|
||||||
|
|
||||||
sessionCtxEACL := session.NewContainerContext()
|
|
||||||
sessionCtxEACL.ForSetEACL()
|
|
||||||
|
|
||||||
return []*session.ContainerContext{sessionCtxPut, sessionCtxDelete, sessionCtxEACL}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, lifetime lifetimeOptions, gateKey *keys.PublicKey) (*bearer.Token, error) {
|
func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, lifetime lifetimeOptions, gateKey *keys.PublicKey) (*bearer.Token, error) {
|
||||||
var ownerID user.ID
|
var ownerID user.ID
|
||||||
user.IDFromKey(&ownerID, (ecdsa.PublicKey)(*gateKey))
|
user.IDFromKey(&ownerID, (ecdsa.PublicKey)(*gateKey))
|
||||||
|
@ -420,30 +379,29 @@ func buildBearerTokens(key *keys.PrivateKey, table *eacl.Table, lifetime lifetim
|
||||||
return bearerTokens, nil
|
return bearerTokens, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildSessionToken(key *keys.PrivateKey, oid *user.ID, lifetime lifetimeOptions, ctx *session.ContainerContext, gateKey *keys.PublicKey) (*session.Token, error) {
|
func buildSessionToken(key *keys.PrivateKey, lifetime lifetimeOptions, ctx sessionTokenContext, gateKey *keys.PublicKey) (*session.Container, error) {
|
||||||
tok := session.NewToken()
|
tok := new(session.Container)
|
||||||
tok.SetContext(ctx)
|
tok.ForVerb(ctx.verb)
|
||||||
uid, err := uuid.New().MarshalBinary()
|
if ctx.containerID != nil {
|
||||||
if err != nil {
|
tok.AppliedTo(*ctx.containerID)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
tok.SetID(uid)
|
|
||||||
tok.SetOwnerID(oid)
|
tok.SetID(uuid.New())
|
||||||
tok.SetSessionKey(gateKey.Bytes())
|
tok.SetAuthKey((*neofsecdsa.PublicKey)(gateKey))
|
||||||
|
|
||||||
tok.SetIat(lifetime.Iat)
|
tok.SetIat(lifetime.Iat)
|
||||||
tok.SetNbf(lifetime.Iat)
|
tok.SetNbf(lifetime.Iat)
|
||||||
tok.SetExp(lifetime.Exp)
|
tok.SetExp(lifetime.Exp)
|
||||||
|
|
||||||
return tok, tok.Sign(&key.PrivateKey)
|
return tok, tok.Sign(key.PrivateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildSessionTokens(key *keys.PrivateKey, oid *user.ID, lifetime lifetimeOptions, ctxs []*session.ContainerContext, gatesKeys []*keys.PublicKey) ([][]*session.Token, error) {
|
func buildSessionTokens(key *keys.PrivateKey, lifetime lifetimeOptions, ctxs []sessionTokenContext, gatesKeys []*keys.PublicKey) ([][]*session.Container, error) {
|
||||||
sessionTokens := make([][]*session.Token, 0, len(gatesKeys))
|
sessionTokens := make([][]*session.Container, 0, len(gatesKeys))
|
||||||
for _, gateKey := range gatesKeys {
|
for _, gateKey := range gatesKeys {
|
||||||
tkns := make([]*session.Token, len(ctxs))
|
tkns := make([]*session.Container, len(ctxs))
|
||||||
for i, ctx := range ctxs {
|
for i, ctx := range ctxs {
|
||||||
tkn, err := buildSessionToken(key, oid, lifetime, ctx, gateKey)
|
tkn, err := buildSessionToken(key, lifetime, ctx, gateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -475,10 +433,7 @@ func createTokens(options *IssueSecretOptions, lifetime lifetimeOptions) ([]*acc
|
||||||
return nil, fmt.Errorf("failed to build context for session token: %w", err)
|
return nil, fmt.Errorf("failed to build context for session token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ownerID user.ID
|
sessionTokens, err := buildSessionTokens(options.NeoFSKey, lifetime, sessionRules, options.GatesPublicKeys)
|
||||||
user.IDFromKey(&ownerID, options.NeoFSKey.PrivateKey.PublicKey)
|
|
||||||
|
|
||||||
sessionTokens, err := buildSessionTokens(options.NeoFSKey, &ownerID, lifetime, sessionRules, options.GatesPublicKeys)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to biuild session token: %w", err)
|
return nil, fmt.Errorf("failed to biuild session token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
package authmate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestContainerSessionRules(t *testing.T) {
|
|
||||||
jsonRules := []byte(`
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"verb": "PUT",
|
|
||||||
"wildcard": true,
|
|
||||||
"containerID": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"verb": "DELETE",
|
|
||||||
"wildcard": true,
|
|
||||||
"containerID": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"verb": "SETEACL",
|
|
||||||
"wildcard": true,
|
|
||||||
"containerID": null
|
|
||||||
}
|
|
||||||
]`)
|
|
||||||
|
|
||||||
sessionContext, err := buildContext(jsonRules)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Len(t, sessionContext, 3)
|
|
||||||
require.True(t, sessionContext[0].IsForPut())
|
|
||||||
require.Nil(t, sessionContext[0].Container())
|
|
||||||
require.True(t, sessionContext[1].IsForDelete())
|
|
||||||
require.Nil(t, sessionContext[1].Container())
|
|
||||||
require.True(t, sessionContext[2].IsForSetEACL())
|
|
||||||
require.Nil(t, sessionContext[2].Container())
|
|
||||||
}
|
|
84
authmate/session_tokens.go
Normal file
84
authmate/session_tokens.go
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
package authmate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
apisession "github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
sessionTokenModel struct {
|
||||||
|
Verb string `json:"verb"`
|
||||||
|
ContainerID string `json:"ContainerID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionTokenContext struct {
|
||||||
|
verb session.ContainerVerb
|
||||||
|
containerID *cid.ID
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *sessionTokenContext) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
var m sessionTokenModel
|
||||||
|
|
||||||
|
if err = json.Unmarshal(data, &m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch m.Verb {
|
||||||
|
case apisession.ContainerVerbPut.String():
|
||||||
|
c.verb = session.VerbContainerPut
|
||||||
|
case apisession.ContainerVerbSetEACL.String():
|
||||||
|
c.verb = session.VerbContainerSetEACL
|
||||||
|
case apisession.ContainerVerbDelete.String():
|
||||||
|
c.verb = session.VerbContainerDelete
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown container token verb %s", m.Verb)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(m.ContainerID) > 0 {
|
||||||
|
c.containerID = new(cid.ID)
|
||||||
|
return c.containerID.DecodeString(m.ContainerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildContext(rules []byte) ([]sessionTokenContext, error) {
|
||||||
|
var sessionCtxs []sessionTokenContext
|
||||||
|
|
||||||
|
if len(rules) != 0 {
|
||||||
|
err := json.Unmarshal(rules, &sessionCtxs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal rules for session token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
containsPut = false
|
||||||
|
containsSetEACL = false
|
||||||
|
)
|
||||||
|
for _, d := range sessionCtxs {
|
||||||
|
if d.verb == session.VerbContainerPut {
|
||||||
|
containsPut = true
|
||||||
|
} else if d.verb == session.VerbContainerSetEACL {
|
||||||
|
containsSetEACL = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if containsPut && !containsSetEACL {
|
||||||
|
sessionCtxs = append(sessionCtxs, sessionTokenContext{
|
||||||
|
verb: session.VerbContainerSetEACL,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return sessionCtxs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return []sessionTokenContext{
|
||||||
|
{verb: session.VerbContainerPut},
|
||||||
|
{verb: session.VerbContainerDelete},
|
||||||
|
{verb: session.VerbContainerSetEACL},
|
||||||
|
}, nil
|
||||||
|
}
|
36
authmate/session_tokens_test.go
Normal file
36
authmate/session_tokens_test.go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package authmate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestContainerSessionRules(t *testing.T) {
|
||||||
|
jsonRules := []byte(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"verb": "PUT",
|
||||||
|
"containerID": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"verb": "DELETE",
|
||||||
|
"containerID": "6CcWg8LkcbfMUC8pt7wiy5zM1fyS3psNoxgfppcCgig1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"verb": "SETEACL"
|
||||||
|
}
|
||||||
|
]`)
|
||||||
|
|
||||||
|
sessionContext, err := buildContext(jsonRules)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Len(t, sessionContext, 3)
|
||||||
|
require.Equal(t, sessionContext[0].verb, session.VerbContainerPut)
|
||||||
|
require.Nil(t, sessionContext[0].containerID)
|
||||||
|
require.Equal(t, sessionContext[1].verb, session.VerbContainerDelete)
|
||||||
|
require.NotNil(t, sessionContext[1].containerID)
|
||||||
|
require.Equal(t, sessionContext[2].verb, session.VerbContainerSetEACL)
|
||||||
|
require.Nil(t, sessionContext[2].containerID)
|
||||||
|
}
|
|
@ -11,7 +11,6 @@ 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/bearer"
|
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
||||||
"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"
|
||||||
|
@ -36,7 +35,7 @@ type ContainerPolicy struct {
|
||||||
type GateData struct {
|
type GateData struct {
|
||||||
AccessKey string
|
AccessKey string
|
||||||
BearerToken *bearer.Token
|
BearerToken *bearer.Token
|
||||||
SessionTokens []*session.Token
|
SessionTokens []*session.Container
|
||||||
GateKey *keys.PublicKey
|
GateKey *keys.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,36 +45,36 @@ func NewGateData(gateKey *keys.PublicKey, bearerTkn *bearer.Token) *GateData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SessionTokenForPut returns the first suitable container session context for PUT operation.
|
// SessionTokenForPut returns the first suitable container session context for PUT operation.
|
||||||
func (g *GateData) SessionTokenForPut() *session.Token {
|
func (g *GateData) SessionTokenForPut() *session.Container {
|
||||||
return g.containerSessionToken(apisession.ContainerVerbPut)
|
return g.containerSessionToken(session.VerbContainerPut)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SessionTokenForDelete returns the first suitable container session context for DELETE operation.
|
// SessionTokenForDelete returns the first suitable container session context for DELETE operation.
|
||||||
func (g *GateData) SessionTokenForDelete() *session.Token {
|
func (g *GateData) SessionTokenForDelete() *session.Container {
|
||||||
return g.containerSessionToken(apisession.ContainerVerbDelete)
|
return g.containerSessionToken(session.VerbContainerDelete)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SessionTokenForSetEACL returns the first suitable container session context for SetEACL operation.
|
// SessionTokenForSetEACL returns the first suitable container session context for SetEACL operation.
|
||||||
func (g *GateData) SessionTokenForSetEACL() *session.Token {
|
func (g *GateData) SessionTokenForSetEACL() *session.Container {
|
||||||
return g.containerSessionToken(apisession.ContainerVerbSetEACL)
|
return g.containerSessionToken(session.VerbContainerSetEACL)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GateData) containerSessionToken(verb apisession.ContainerSessionVerb) *session.Token {
|
func (g *GateData) containerSessionToken(verb session.ContainerVerb) *session.Container {
|
||||||
for _, sessionToken := range g.SessionTokens {
|
for _, sessionToken := range g.SessionTokens {
|
||||||
switch ctx := sessionToken.Context().(type) {
|
if isAppropriateContainerContext(sessionToken, verb) {
|
||||||
case *session.ContainerContext:
|
|
||||||
if isAppropriateContainerContext(ctx, verb) {
|
|
||||||
return sessionToken
|
return sessionToken
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isAppropriateContainerContext(ctx *session.ContainerContext, verb apisession.ContainerSessionVerb) bool {
|
func isAppropriateContainerContext(tok *session.Container, verb session.ContainerVerb) bool {
|
||||||
return verb == apisession.ContainerVerbPut && ctx.IsForPut() ||
|
switch verb {
|
||||||
verb == apisession.ContainerVerbDelete && ctx.IsForDelete() ||
|
case session.VerbContainerSetEACL, session.VerbContainerDelete, session.VerbContainerPut:
|
||||||
verb == apisession.ContainerVerbSetEACL && ctx.IsForSetEACL()
|
return tok.AssertVerb(verb)
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Secrets represents AccessKey and the key to encrypt gate tokens.
|
// Secrets represents AccessKey and the key to encrypt gate tokens.
|
||||||
|
@ -179,11 +178,7 @@ func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *keys.PrivateK
|
||||||
encBearer := gate.BearerToken.Marshal()
|
encBearer := gate.BearerToken.Marshal()
|
||||||
encSessions := make([][]byte, len(gate.SessionTokens))
|
encSessions := make([][]byte, len(gate.SessionTokens))
|
||||||
for i, sessionToken := range gate.SessionTokens {
|
for i, sessionToken := range gate.SessionTokens {
|
||||||
encSession, err := sessionToken.Marshal()
|
encSessions[i] = sessionToken.Marshal()
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%w, sender = %d", err, i)
|
|
||||||
}
|
|
||||||
encSessions[i] = encSession
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens := new(Tokens)
|
tokens := new(Tokens)
|
||||||
|
@ -232,9 +227,9 @@ func decodeGate(gate *AccessBox_Gate, owner *keys.PrivateKey, sender *keys.Publi
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionTkns := make([]*session.Token, len(tokens.SessionTokens))
|
sessionTkns := make([]*session.Container, len(tokens.SessionTokens))
|
||||||
for i, encSessionToken := range tokens.SessionTokens {
|
for i, encSessionToken := range tokens.SessionTokens {
|
||||||
sessionTkn := session.NewToken()
|
sessionTkn := new(session.Container)
|
||||||
if err := sessionTkn.Unmarshal(encSessionToken); err != nil {
|
if err := sessionTkn.Unmarshal(encSessionToken); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
||||||
|
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -73,7 +74,7 @@ func Test_session_token_in_access_box(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
box *AccessBox
|
box *AccessBox
|
||||||
box2 AccessBox
|
box2 AccessBox
|
||||||
tkn = session.NewToken()
|
tkn = new(session.Container)
|
||||||
)
|
)
|
||||||
|
|
||||||
sec, err := keys.NewPrivateKey()
|
sec, err := keys.NewPrivateKey()
|
||||||
|
@ -82,17 +83,13 @@ func Test_session_token_in_access_box(t *testing.T) {
|
||||||
cred, err := keys.NewPrivateKey()
|
cred, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tok := session.NewToken()
|
tkn.SetID(uuid.New())
|
||||||
tok.SetContext(session.NewContainerContext())
|
tkn.SetAuthKey((*neofsecdsa.PublicKey)(sec.PublicKey()))
|
||||||
uid, err := uuid.New().MarshalBinary()
|
require.NoError(t, tkn.Sign(sec.PrivateKey))
|
||||||
require.NoError(t, err)
|
|
||||||
tok.SetID(uid)
|
|
||||||
tok.SetSessionKey(sec.PublicKey().Bytes())
|
|
||||||
require.NoError(t, tkn.Sign(&sec.PrivateKey))
|
|
||||||
|
|
||||||
var newTkn bearer.Token
|
var newTkn bearer.Token
|
||||||
gate := NewGateData(cred.PublicKey(), &newTkn)
|
gate := NewGateData(cred.PublicKey(), &newTkn)
|
||||||
gate.SessionTokens = []*session.Token{tkn}
|
gate.SessionTokens = []*session.Container{tkn}
|
||||||
box, _, err = PackTokens([]*GateData{gate})
|
box, _, err = PackTokens([]*GateData{gate})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -105,7 +102,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, []*session.Token{tkn}, tkns.SessionTokens)
|
require.Equal(t, []*session.Container{tkn}, tkns.SessionTokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_accessbox_multiple_keys(t *testing.T) {
|
func Test_accessbox_multiple_keys(t *testing.T) {
|
||||||
|
|
|
@ -203,22 +203,25 @@ where content of `session.json`:
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"verb": "PUT",
|
"verb": "PUT",
|
||||||
"wildcard": true,
|
|
||||||
"containerID": null
|
"containerID": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"verb": "DELETE",
|
"verb": "DELETE",
|
||||||
"wildcard": true,
|
|
||||||
"containerID": null
|
"containerID": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"verb": "SETEACL",
|
"verb": "SETEACL",
|
||||||
"wildcard": true,
|
|
||||||
"containerID": null
|
"containerID": null
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Available `verb` values: `PUT`, `DELETE`, `SETEACL`.
|
||||||
|
|
||||||
|
If `containerID` is `null` or omitted, then session token rule will be applied
|
||||||
|
to all containers. Otherwise, specify `containerID` value in human-redabale
|
||||||
|
format (base58 encoded string).
|
||||||
|
|
||||||
> **_NB!_** To create buckets in NeoFS it's necessary to have session tokens with `PUT` and `SETEACL` permissions, that's why
|
> **_NB!_** To create buckets in NeoFS it's necessary to have session tokens with `PUT` and `SETEACL` permissions, that's why
|
||||||
the authmate creates a `SETEACL` session token automatically in case when a user specified the token rule with `PUT` and
|
the authmate creates a `SETEACL` session token automatically in case when a user specified the token rule with `PUT` and
|
||||||
forgot about the rule with `SETEACL`.
|
forgot about the rule with `SETEACL`.
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -13,7 +13,7 @@ require (
|
||||||
github.com/nats-io/nats.go v1.13.1-0.20220121202836-972a071d373d
|
github.com/nats-io/nats.go v1.13.1-0.20220121202836-972a071d373d
|
||||||
github.com/nspcc-dev/neo-go v0.98.2
|
github.com/nspcc-dev/neo-go v0.98.2
|
||||||
github.com/nspcc-dev/neofs-api-go/v2 v2.12.1
|
github.com/nspcc-dev/neofs-api-go/v2 v2.12.1
|
||||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220424111116-497053c785f5
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220504192402-12ea1e8d740f
|
||||||
github.com/prometheus/client_golang v1.11.0
|
github.com/prometheus/client_golang v1.11.0
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.1
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -306,8 +306,10 @@ github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnB
|
||||||
github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4=
|
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659/go.mod h1:/jay1lr3w7NQd/VDBkEhkJmDmyPNsu4W+QV2obsUV40=
|
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659/go.mod h1:/jay1lr3w7NQd/VDBkEhkJmDmyPNsu4W+QV2obsUV40=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220424111116-497053c785f5 h1:upiT6iVOy81tiY2x593E8+mxpb9BuW3fsvKFdqdXenk=
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220504122248-539ac9915ed0 h1:tEwL29lFFX983YLUWc5rmnw5MK/z4id0KlBWuUboe+E=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220424111116-497053c785f5/go.mod h1:u567oWTnAyGXbPWMrbcN0NB5zCPF+PqkaKg+vcijcho=
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220504122248-539ac9915ed0/go.mod h1:u567oWTnAyGXbPWMrbcN0NB5zCPF+PqkaKg+vcijcho=
|
||||||
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220504192402-12ea1e8d740f h1:cMxSTUkugwaBFL7dEYirmjOEQ2p12phcpKO1Z3UhP64=
|
||||||
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220504192402-12ea1e8d740f/go.mod h1:u567oWTnAyGXbPWMrbcN0NB5zCPF+PqkaKg+vcijcho=
|
||||||
github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
|
github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
||||||
|
|
|
@ -197,7 +197,7 @@ func (x *NeoFS) ContainerEACL(ctx context.Context, id cid.ID) (*eacl.Table, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteContainer implements neofs.NeoFS interface method.
|
// DeleteContainer implements neofs.NeoFS interface method.
|
||||||
func (x *NeoFS) DeleteContainer(ctx context.Context, id cid.ID, token *session.Token) error {
|
func (x *NeoFS) DeleteContainer(ctx context.Context, id cid.ID, token *session.Container) error {
|
||||||
var prm pool.PrmContainerDelete
|
var prm pool.PrmContainerDelete
|
||||||
prm.SetContainerID(id)
|
prm.SetContainerID(id)
|
||||||
prm.SetSessionToken(*token)
|
prm.SetSessionToken(*token)
|
||||||
|
|
Loading…
Reference in a new issue