forked from TrueCloudLab/frostfs-s3-gw
[#271] Add random key for no sign requests
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
71f578a883
commit
ae87effb28
11 changed files with 133 additions and 90 deletions
|
@ -1,6 +1,7 @@
|
||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -141,15 +142,30 @@ func (h *handler) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *handler) gateKey(ctx context.Context) (*keys.PublicKey, error) {
|
||||||
|
gateKey := h.obj.EphemeralKey()
|
||||||
|
box, err := layer.GetBoxData(ctx)
|
||||||
|
if err == nil {
|
||||||
|
if box.Gate.GateKey == nil {
|
||||||
|
return nil, fmt.Errorf("gate key must not be nil")
|
||||||
|
}
|
||||||
|
gateKey = box.Gate.GateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
return gateKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (h *handler) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
reqInfo := api.GetReqInfo(r.Context())
|
||||||
err error
|
gateKey, err := h.gateKey(r.Context())
|
||||||
reqInfo = api.GetReqInfo(r.Context())
|
if err != nil {
|
||||||
)
|
h.logAndSendError(w, "couldn't get gate key", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
list := &AccessControlPolicy{}
|
list := &AccessControlPolicy{}
|
||||||
if r.ContentLength == 0 {
|
if r.ContentLength == 0 {
|
||||||
list, err = parseACLHeaders(r)
|
list, err = parseACLHeaders(r.Header, gateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not parse bucket acl", reqInfo, err)
|
h.logAndSendError(w, "could not parse bucket acl", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -231,15 +247,17 @@ func (h *handler) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
reqInfo := api.GetReqInfo(r.Context())
|
||||||
err error
|
versionID := reqInfo.URL.Query().Get(api.QueryVersionID)
|
||||||
reqInfo = api.GetReqInfo(r.Context())
|
gateKey, err := h.gateKey(r.Context())
|
||||||
versionID = reqInfo.URL.Query().Get(api.QueryVersionID)
|
if err != nil {
|
||||||
)
|
h.logAndSendError(w, "couldn't get gate key", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
list := &AccessControlPolicy{}
|
list := &AccessControlPolicy{}
|
||||||
if r.ContentLength == 0 {
|
if r.ContentLength == 0 {
|
||||||
list, err = parseACLHeaders(r)
|
list, err = parseACLHeaders(r.Header, gateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not parse bucket acl", reqInfo, err)
|
h.logAndSendError(w, "could not parse bucket acl", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -336,16 +354,8 @@ func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request)
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseACLHeaders(r *http.Request) (*AccessControlPolicy, error) {
|
func parseACLHeaders(header http.Header, gateKey *keys.PublicKey) (*AccessControlPolicy, error) {
|
||||||
var err error
|
var err error
|
||||||
box, err := layer.GetBoxData(r.Context())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if box.Gate.GateKey == nil {
|
|
||||||
return nil, fmt.Errorf("gate key must not be nil")
|
|
||||||
}
|
|
||||||
gateKey := box.Gate.GateKey
|
|
||||||
|
|
||||||
acp := &AccessControlPolicy{Owner: Owner{
|
acp := &AccessControlPolicy{Owner: Owner{
|
||||||
ID: hex.EncodeToString(gateKey.Bytes()),
|
ID: hex.EncodeToString(gateKey.Bytes()),
|
||||||
DisplayName: gateKey.Address(),
|
DisplayName: gateKey.Address(),
|
||||||
|
@ -359,18 +369,18 @@ func parseACLHeaders(r *http.Request) (*AccessControlPolicy, error) {
|
||||||
Permission: aclFullControl,
|
Permission: aclFullControl,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
cannedACL := r.Header.Get(api.AmzACL)
|
cannedACL := header.Get(api.AmzACL)
|
||||||
if cannedACL != "" {
|
if cannedACL != "" {
|
||||||
return addPredefinedACP(acp, cannedACL)
|
return addPredefinedACP(acp, cannedACL)
|
||||||
}
|
}
|
||||||
|
|
||||||
if acp.AccessControlList, err = addGrantees(acp.AccessControlList, r.Header, api.AmzGrantFullControl); err != nil {
|
if acp.AccessControlList, err = addGrantees(acp.AccessControlList, header, api.AmzGrantFullControl); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if acp.AccessControlList, err = addGrantees(acp.AccessControlList, r.Header, api.AmzGrantRead); err != nil {
|
if acp.AccessControlList, err = addGrantees(acp.AccessControlList, header, api.AmzGrantRead); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if acp.AccessControlList, err = addGrantees(acp.AccessControlList, r.Header, api.AmzGrantWrite); err != nil {
|
if acp.AccessControlList, err = addGrantees(acp.AccessControlList, header, api.AmzGrantWrite); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
@ -14,7 +13,6 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api"
|
"github.com/nspcc-dev/neofs-s3-gw/api"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -562,14 +560,6 @@ func TestParseCannedACLHeaders(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
box := &accessbox.Box{
|
|
||||||
Gate: &accessbox.GateData{
|
|
||||||
GateKey: key.PublicKey(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
ctx := context.Background()
|
|
||||||
ctx = context.WithValue(ctx, api.BoxData, box)
|
|
||||||
|
|
||||||
expectedACL := &AccessControlPolicy{
|
expectedACL := &AccessControlPolicy{
|
||||||
Owner: Owner{
|
Owner: Owner{
|
||||||
ID: id,
|
ID: id,
|
||||||
|
@ -591,7 +581,7 @@ func TestParseCannedACLHeaders(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
actualACL, err := parseACLHeaders(req.WithContext(ctx))
|
actualACL, err := parseACLHeaders(req.Header, key.PublicKey())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expectedACL, actualACL)
|
require.Equal(t, expectedACL, actualACL)
|
||||||
}
|
}
|
||||||
|
@ -611,14 +601,6 @@ func TestParseACLHeaders(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
box := &accessbox.Box{
|
|
||||||
Gate: &accessbox.GateData{
|
|
||||||
GateKey: key.PublicKey(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
ctx := context.Background()
|
|
||||||
ctx = context.WithValue(ctx, api.BoxData, box)
|
|
||||||
|
|
||||||
expectedACL := &AccessControlPolicy{
|
expectedACL := &AccessControlPolicy{
|
||||||
Owner: Owner{
|
Owner: Owner{
|
||||||
ID: id,
|
ID: id,
|
||||||
|
@ -664,7 +646,7 @@ func TestParseACLHeaders(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
actualACL, err := parseACLHeaders(req.WithContext(ctx))
|
actualACL, err := parseACLHeaders(req.Header, key.PublicKey())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expectedACL, actualACL)
|
require.Equal(t, expectedACL, actualACL)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
|
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
|
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
|
||||||
|
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -422,7 +423,11 @@ func containsACLHeaders(r *http.Request) bool {
|
||||||
|
|
||||||
func (h *handler) getNewEAclTable(r *http.Request, objInfo *data.ObjectInfo) (*eacl.Table, error) {
|
func (h *handler) getNewEAclTable(r *http.Request, objInfo *data.ObjectInfo) (*eacl.Table, error) {
|
||||||
var newEaclTable *eacl.Table
|
var newEaclTable *eacl.Table
|
||||||
objectACL, err := parseACLHeaders(r)
|
gateKey, err := h.gateKey(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
objectACL, err := parseACLHeaders(r.Header, gateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not parse object acl: %w", err)
|
return nil, fmt.Errorf("could not parse object acl: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -508,7 +513,13 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bktACL, err := parseACLHeaders(r)
|
gateKey, err := h.gateKey(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(w, "couldn't get gate key", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bktACL, err := parseACLHeaders(r.Header, gateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not parse bucket acl", reqInfo, err)
|
h.logAndSendError(w, "could not parse bucket acl", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -527,14 +538,15 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p.BoxData, err = layer.GetBoxData(r.Context())
|
var policies []*accessbox.ContainerPolicy
|
||||||
if err != nil {
|
boxData, err := layer.GetBoxData(r.Context())
|
||||||
h.logAndSendError(w, "could not get boxData", reqInfo, err)
|
if err == nil {
|
||||||
return
|
policies = boxData.Policies
|
||||||
|
p.SessionToken = boxData.Gate.SessionToken
|
||||||
}
|
}
|
||||||
|
|
||||||
if createParams.LocationConstraint != "" {
|
if createParams.LocationConstraint != "" {
|
||||||
for _, placementPolicy := range p.BoxData.Policies {
|
for _, placementPolicy := range policies {
|
||||||
if placementPolicy.LocationConstraint == createParams.LocationConstraint {
|
if placementPolicy.LocationConstraint == createParams.LocationConstraint {
|
||||||
p.Policy = placementPolicy.Policy
|
p.Policy = placementPolicy.Policy
|
||||||
break
|
break
|
||||||
|
|
|
@ -28,17 +28,16 @@ type (
|
||||||
|
|
||||||
func (n *layer) containerInfo(ctx context.Context, cid *cid.ID) (*data.BucketInfo, error) {
|
func (n *layer) containerInfo(ctx context.Context, cid *cid.ID) (*data.BucketInfo, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
res *container.Container
|
res *container.Container
|
||||||
rid = api.GetRequestID(ctx)
|
rid = api.GetRequestID(ctx)
|
||||||
bearerOpt = n.BearerOpt(ctx)
|
|
||||||
|
|
||||||
info = &data.BucketInfo{
|
info = &data.BucketInfo{
|
||||||
CID: cid,
|
CID: cid,
|
||||||
Name: cid.String(),
|
Name: cid.String(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
res, err = n.pool.GetContainer(ctx, cid, bearerOpt)
|
res, err = n.pool.GetContainer(ctx, cid, n.CallOptions(ctx)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.log.Error("could not fetch container",
|
n.log.Error("could not fetch container",
|
||||||
zap.Stringer("cid", cid),
|
zap.Stringer("cid", cid),
|
||||||
|
@ -86,13 +85,12 @@ func (n *layer) containerInfo(ctx context.Context, cid *cid.ID) (*data.BucketInf
|
||||||
|
|
||||||
func (n *layer) containerList(ctx context.Context) ([]*data.BucketInfo, error) {
|
func (n *layer) containerList(ctx context.Context) ([]*data.BucketInfo, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
own = n.Owner(ctx)
|
own = n.Owner(ctx)
|
||||||
bearerOpt = n.BearerOpt(ctx)
|
res []*cid.ID
|
||||||
res []*cid.ID
|
rid = api.GetRequestID(ctx)
|
||||||
rid = api.GetRequestID(ctx)
|
|
||||||
)
|
)
|
||||||
res, err = n.pool.ListContainers(ctx, own, bearerOpt)
|
res, err = n.pool.ListContainers(ctx, own, n.CallOptions(ctx)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.log.Error("could not fetch container",
|
n.log.Error("could not fetch container",
|
||||||
zap.String("request_id", rid),
|
zap.String("request_id", rid),
|
||||||
|
@ -130,7 +128,7 @@ func (n *layer) createContainer(ctx context.Context, p *CreateBucketParams) (*ci
|
||||||
container.WithAttribute(container.AttributeName, p.Name),
|
container.WithAttribute(container.AttributeName, p.Name),
|
||||||
container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(bktInfo.Created.Unix(), 10)))
|
container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(bktInfo.Created.Unix(), 10)))
|
||||||
|
|
||||||
cnr.SetSessionToken(p.BoxData.Gate.SessionToken)
|
cnr.SetSessionToken(p.SessionToken)
|
||||||
cnr.SetOwnerID(bktInfo.Owner)
|
cnr.SetOwnerID(bktInfo.Owner)
|
||||||
|
|
||||||
if bktInfo.CID, err = n.pool.PutContainer(ctx, cnr); err != nil {
|
if bktInfo.CID, err = n.pool.PutContainer(ctx, cnr); err != nil {
|
||||||
|
|
|
@ -6,20 +6,24 @@ import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/client"
|
"github.com/nspcc-dev/neofs-api-go/pkg/client"
|
||||||
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
|
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
|
"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
|
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/pkg/session"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api"
|
"github.com/nspcc-dev/neofs-s3-gw/api"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
|
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
|
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
|
||||||
|
"github.com/nspcc-dev/neofs-s3-gw/authmate"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
|
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -29,6 +33,7 @@ type (
|
||||||
layer struct {
|
layer struct {
|
||||||
pool pool.Pool
|
pool pool.Pool
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
|
anonKey AnonymousKey
|
||||||
listsCache *cache.ObjectsListCache
|
listsCache *cache.ObjectsListCache
|
||||||
objCache *cache.ObjectsCache
|
objCache *cache.ObjectsCache
|
||||||
namesCache *cache.ObjectsNameCache
|
namesCache *cache.ObjectsNameCache
|
||||||
|
@ -36,6 +41,11 @@ type (
|
||||||
systemCache *cache.SystemCache
|
systemCache *cache.SystemCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AnonymousKey contains data for anonymous requests.
|
||||||
|
AnonymousKey struct {
|
||||||
|
Key *keys.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
// CachesConfig contains params for caches.
|
// CachesConfig contains params for caches.
|
||||||
CachesConfig struct {
|
CachesConfig struct {
|
||||||
Objects *cache.Config
|
Objects *cache.Config
|
||||||
|
@ -112,11 +122,11 @@ type (
|
||||||
}
|
}
|
||||||
// CreateBucketParams stores bucket create request parameters.
|
// CreateBucketParams stores bucket create request parameters.
|
||||||
CreateBucketParams struct {
|
CreateBucketParams struct {
|
||||||
Name string
|
Name string
|
||||||
ACL uint32
|
ACL uint32
|
||||||
Policy *netmap.PlacementPolicy
|
Policy *netmap.PlacementPolicy
|
||||||
EACL *eacl.Table
|
EACL *eacl.Table
|
||||||
BoxData *accessbox.Box
|
SessionToken *session.Token
|
||||||
}
|
}
|
||||||
// PutBucketACLParams stores put bucket acl request parameters.
|
// PutBucketACLParams stores put bucket acl request parameters.
|
||||||
PutBucketACLParams struct {
|
PutBucketACLParams struct {
|
||||||
|
@ -171,6 +181,8 @@ type (
|
||||||
Client interface {
|
Client interface {
|
||||||
NeoFS
|
NeoFS
|
||||||
|
|
||||||
|
EphemeralKey() *keys.PublicKey
|
||||||
|
|
||||||
PutBucketVersioning(ctx context.Context, p *PutVersioningParams) (*data.ObjectInfo, error)
|
PutBucketVersioning(ctx context.Context, p *PutVersioningParams) (*data.ObjectInfo, error)
|
||||||
GetBucketVersioning(ctx context.Context, name string) (*BucketSettings, error)
|
GetBucketVersioning(ctx context.Context, name string) (*BucketSettings, error)
|
||||||
|
|
||||||
|
@ -228,10 +240,11 @@ func DefaultCachesConfigs() *CachesConfig {
|
||||||
|
|
||||||
// NewLayer creates instance of layer. It checks credentials
|
// NewLayer creates instance of layer. It checks credentials
|
||||||
// and establishes gRPC connection with node.
|
// and establishes gRPC connection with node.
|
||||||
func NewLayer(log *zap.Logger, conns pool.Pool, config *CachesConfig) Client {
|
func NewLayer(log *zap.Logger, conns pool.Pool, config *CachesConfig, anonKey AnonymousKey) Client {
|
||||||
return &layer{
|
return &layer{
|
||||||
pool: conns,
|
pool: conns,
|
||||||
log: log,
|
log: log,
|
||||||
|
anonKey: anonKey,
|
||||||
listsCache: cache.NewObjectsListCache(config.ObjectsList),
|
listsCache: cache.NewObjectsListCache(config.ObjectsList),
|
||||||
objCache: cache.New(config.Objects),
|
objCache: cache.New(config.Objects),
|
||||||
namesCache: cache.NewObjectsNameCache(config.Names),
|
namesCache: cache.NewObjectsNameCache(config.Names),
|
||||||
|
@ -240,22 +253,40 @@ func NewLayer(log *zap.Logger, conns pool.Pool, config *CachesConfig) Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *layer) EphemeralKey() *keys.PublicKey {
|
||||||
|
return n.anonKey.Key.PublicKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
// randomSession returns client.WithSession for ephemeral key or nil if access box matches gate key.
|
||||||
|
func (n *layer) randomSession(ctx context.Context) client.CallOption {
|
||||||
|
c, _, err := n.pool.Connection()
|
||||||
|
if err != nil {
|
||||||
|
return client.WithSession(nil)
|
||||||
|
}
|
||||||
|
st, err := c.CreateSession(ctx, math.MaxUint64, client.WithKey(&n.anonKey.Key.PrivateKey))
|
||||||
|
if err != nil {
|
||||||
|
return client.WithSession(nil)
|
||||||
|
}
|
||||||
|
return client.WithSession(st)
|
||||||
|
}
|
||||||
|
|
||||||
// Owner returns owner id from BearerToken (context) or from client owner.
|
// Owner returns owner id from BearerToken (context) or from client owner.
|
||||||
func (n *layer) Owner(ctx context.Context) *owner.ID {
|
func (n *layer) Owner(ctx context.Context) *owner.ID {
|
||||||
if data, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && data != nil && data.Gate != nil {
|
if data, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && data != nil && data.Gate != nil {
|
||||||
return data.Gate.BearerToken.Issuer()
|
return data.Gate.BearerToken.Issuer()
|
||||||
}
|
}
|
||||||
|
|
||||||
return n.pool.OwnerID()
|
id, _ := authmate.OwnerIDFromNeoFSKey(n.EphemeralKey())
|
||||||
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
// BearerOpt returns client.WithBearer call option with token from context or with nil token.
|
// CallOptions returns []client.CallOption options: client.WithBearer and client.WithKey.
|
||||||
func (n *layer) BearerOpt(ctx context.Context) client.CallOption {
|
func (n *layer) CallOptions(ctx context.Context) []client.CallOption {
|
||||||
if data, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && data != nil && data.Gate != nil {
|
if data, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && data != nil && data.Gate != nil {
|
||||||
return client.WithBearer(data.Gate.BearerToken)
|
return []client.CallOption{client.WithBearer(data.Gate.BearerToken)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.WithBearer(nil)
|
return []client.CallOption{client.WithKey(&n.anonKey.Key.PrivateKey), n.randomSession(ctx)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SessionOpt returns client.WithSession call option with token from context or with nil token.
|
// SessionOpt returns client.WithSession call option with token from context or with nil token.
|
||||||
|
@ -270,7 +301,7 @@ func (n *layer) SessionOpt(ctx context.Context) client.CallOption {
|
||||||
// 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)
|
||||||
return n.pool.GetObject(ctx, ops, n.BearerOpt(ctx))
|
return n.pool.GetObject(ctx, ops, n.CallOptions(ctx)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBucketInfo returns bucket info by name.
|
// GetBucketInfo returns bucket info by name.
|
||||||
|
|
|
@ -88,7 +88,8 @@ func (n *layer) objectSearch(ctx context.Context, p *findParams) ([]*object.ID,
|
||||||
} else if prefix != "" {
|
} else if prefix != "" {
|
||||||
opts.AddFilter(object.AttributeFileName, prefix, object.MatchCommonPrefix)
|
opts.AddFilter(object.AttributeFileName, prefix, object.MatchCommonPrefix)
|
||||||
}
|
}
|
||||||
return n.pool.SearchObject(ctx, new(client.SearchObjectParams).WithContainerID(p.cid).WithSearchFilters(opts), n.BearerOpt(ctx))
|
searchParams := new(client.SearchObjectParams).WithContainerID(p.cid).WithSearchFilters(opts)
|
||||||
|
return n.pool.SearchObject(ctx, searchParams, n.CallOptions(ctx)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAddress(cid *cid.ID, oid *object.ID) *object.Address {
|
func newAddress(cid *cid.ID, oid *object.ID) *object.Address {
|
||||||
|
@ -101,7 +102,7 @@ func newAddress(cid *cid.ID, oid *object.ID) *object.Address {
|
||||||
// objectHead returns all object's headers.
|
// objectHead returns all object's headers.
|
||||||
func (n *layer) objectHead(ctx context.Context, cid *cid.ID, oid *object.ID) (*object.Object, error) {
|
func (n *layer) objectHead(ctx context.Context, cid *cid.ID, oid *object.ID) (*object.Object, error) {
|
||||||
ops := new(client.ObjectHeaderParams).WithAddress(newAddress(cid, oid)).WithAllFields()
|
ops := new(client.ObjectHeaderParams).WithAddress(newAddress(cid, oid)).WithAllFields()
|
||||||
return n.pool.GetObjectHeader(ctx, ops, n.BearerOpt(ctx))
|
return n.pool.GetObjectHeader(ctx, ops, n.CallOptions(ctx)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// objectGetWithPayloadWriter and write it into provided io.Reader.
|
// objectGetWithPayloadWriter and write it into provided io.Reader.
|
||||||
|
@ -109,20 +110,20 @@ func (n *layer) objectGetWithPayloadWriter(ctx context.Context, p *getParams) (*
|
||||||
// prepare length/offset writer
|
// prepare length/offset writer
|
||||||
w := newWriter(p.Writer, p.offset, p.length)
|
w := newWriter(p.Writer, p.offset, p.length)
|
||||||
ops := new(client.GetObjectParams).WithAddress(newAddress(p.cid, p.oid)).WithPayloadWriter(w)
|
ops := new(client.GetObjectParams).WithAddress(newAddress(p.cid, p.oid)).WithPayloadWriter(w)
|
||||||
return n.pool.GetObject(ctx, ops, n.BearerOpt(ctx))
|
return n.pool.GetObject(ctx, ops, n.CallOptions(ctx)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// objectGet returns an object with payload in the object.
|
// objectGet returns an object with payload in the object.
|
||||||
func (n *layer) objectGet(ctx context.Context, cid *cid.ID, oid *object.ID) (*object.Object, error) {
|
func (n *layer) objectGet(ctx context.Context, cid *cid.ID, oid *object.ID) (*object.Object, error) {
|
||||||
ops := new(client.GetObjectParams).WithAddress(newAddress(cid, oid))
|
ops := new(client.GetObjectParams).WithAddress(newAddress(cid, oid))
|
||||||
return n.pool.GetObject(ctx, ops, n.BearerOpt(ctx))
|
return n.pool.GetObject(ctx, ops, n.CallOptions(ctx)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// objectRange gets object range and writes it into provided io.Writer.
|
// objectRange gets object range and writes it into provided io.Writer.
|
||||||
func (n *layer) objectRange(ctx context.Context, p *getParams) ([]byte, error) {
|
func (n *layer) objectRange(ctx context.Context, p *getParams) ([]byte, error) {
|
||||||
w := newWriter(p.Writer, p.offset, p.length)
|
w := newWriter(p.Writer, p.offset, p.length)
|
||||||
ops := new(client.RangeDataParams).WithAddress(newAddress(p.cid, p.oid)).WithDataWriter(w).WithRange(p.Range)
|
ops := new(client.RangeDataParams).WithAddress(newAddress(p.cid, p.oid)).WithDataWriter(w).WithRange(p.Range)
|
||||||
return n.pool.ObjectPayloadRangeData(ctx, ops, n.BearerOpt(ctx))
|
return n.pool.ObjectPayloadRangeData(ctx, ops, n.CallOptions(ctx)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// objectPut into NeoFS, took payload from io.Reader.
|
// objectPut into NeoFS, took payload from io.Reader.
|
||||||
|
@ -151,7 +152,7 @@ func (n *layer) objectPut(ctx context.Context, bkt *data.BucketInfo, p *PutObjec
|
||||||
rawObject := formRawObject(p, bkt.CID, own, obj)
|
rawObject := formRawObject(p, bkt.CID, own, obj)
|
||||||
|
|
||||||
ops := new(client.PutObjectParams).WithObject(rawObject.Object()).WithPayloadReader(r)
|
ops := new(client.PutObjectParams).WithObject(rawObject.Object()).WithPayloadReader(r)
|
||||||
oid, err := n.pool.PutObject(ctx, ops, n.BearerOpt(ctx))
|
oid, err := n.pool.PutObject(ctx, ops, n.CallOptions(ctx)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -380,7 +381,7 @@ func (n *layer) objectDelete(ctx context.Context, cid *cid.ID, oid *object.ID) e
|
||||||
dop := new(client.DeleteObjectParams)
|
dop := new(client.DeleteObjectParams)
|
||||||
dop.WithAddress(address)
|
dop.WithAddress(address)
|
||||||
n.objCache.Delete(address)
|
n.objCache.Delete(address)
|
||||||
return n.pool.DeleteObject(ctx, dop, n.BearerOpt(ctx))
|
return n.pool.DeleteObject(ctx, dop, n.CallOptions(ctx)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListObjectsV1 returns objects in a bucket for requests of Version 1.
|
// ListObjectsV1 returns objects in a bucket for requests of Version 1.
|
||||||
|
|
|
@ -98,7 +98,7 @@ func (n *layer) putSystemObjectIntoNeoFS(ctx context.Context, p *PutSystemObject
|
||||||
raw.SetAttributes(attributes...)
|
raw.SetAttributes(attributes...)
|
||||||
|
|
||||||
ops := new(client.PutObjectParams).WithObject(raw.Object()).WithPayloadReader(p.Reader)
|
ops := new(client.PutObjectParams).WithObject(raw.Object()).WithPayloadReader(p.Reader)
|
||||||
oid, err := n.pool.PutObject(ctx, ops, n.BearerOpt(ctx))
|
oid, err := n.pool.PutObject(ctx, ops, n.CallOptions(ctx)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,7 +346,7 @@ func prepareContext(t *testing.T, cachesConfig ...*CachesConfig) *testContext {
|
||||||
|
|
||||||
return &testContext{
|
return &testContext{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
layer: NewLayer(l, tp, config),
|
layer: NewLayer(l, tp, config, AnonymousKey{Key: key}),
|
||||||
bkt: bktName,
|
bkt: bktName,
|
||||||
bktID: bktID,
|
bktID: bktID,
|
||||||
obj: "obj1",
|
obj: "obj1",
|
||||||
|
|
|
@ -24,7 +24,7 @@ func AttachUserAuth(router *mux.Router, center auth.Center, log *zap.Logger) {
|
||||||
box, err := center.Authenticate(r)
|
box, err := center.Authenticate(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == auth.ErrNoAuthorizationHeader {
|
if err == auth.ErrNoAuthorizationHeader {
|
||||||
log.Debug("couldn't receive bearer token, using neofs-key")
|
log.Debug("couldn't receive access box for gate key, random key will be used")
|
||||||
ctx = r.Context()
|
ctx = r.Context()
|
||||||
} else {
|
} else {
|
||||||
log.Error("failed to pass authentication", zap.Error(err))
|
log.Error("failed to pass authentication", zap.Error(err))
|
||||||
|
|
|
@ -240,7 +240,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
|
||||||
|
|
||||||
box.ContainerPolicy = policies
|
box.ContainerPolicy = policies
|
||||||
|
|
||||||
oid, err := ownerIDFromNeoFSKey(options.NeoFSKey.PublicKey())
|
oid, err := OwnerIDFromNeoFSKey(options.NeoFSKey.PublicKey())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -391,7 +391,7 @@ func buildContext(rules []byte) (*session.ContainerContext, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, lifetime lifetimeOptions, gateKey *keys.PublicKey) (*token.BearerToken, error) {
|
func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, lifetime lifetimeOptions, gateKey *keys.PublicKey) (*token.BearerToken, error) {
|
||||||
oid, err := ownerIDFromNeoFSKey(gateKey)
|
oid, err := OwnerIDFromNeoFSKey(gateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -466,7 +466,7 @@ func createTokens(options *IssueSecretOptions, lifetime lifetimeOptions, cid *ci
|
||||||
if err != nil {
|
if err != nil {
|
||||||
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)
|
||||||
}
|
}
|
||||||
oid, err := ownerIDFromNeoFSKey(options.NeoFSKey.PublicKey())
|
oid, err := OwnerIDFromNeoFSKey(options.NeoFSKey.PublicKey())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -483,7 +483,7 @@ func createTokens(options *IssueSecretOptions, lifetime lifetimeOptions, cid *ci
|
||||||
return gates, nil
|
return gates, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ownerIDFromNeoFSKey(key *keys.PublicKey) (*owner.ID, error) {
|
func OwnerIDFromNeoFSKey(key *keys.PublicKey) (*owner.ID, error) {
|
||||||
wallet, err := owner.NEO3WalletFromPublicKey((*ecdsa.PublicKey)(key))
|
wallet, err := owner.NEO3WalletFromPublicKey((*ecdsa.PublicKey)(key))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -112,10 +112,19 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
|
||||||
l.Fatal("failed to create connection pool", zap.Error(err))
|
l.Fatal("failed to create connection pool", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prepare random key for anonymous requests
|
||||||
|
randomKey, err := keys.NewPrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
l.Fatal("couldn't generate random key", zap.Error(err))
|
||||||
|
}
|
||||||
|
anonKey := layer.AnonymousKey{
|
||||||
|
Key: randomKey,
|
||||||
|
}
|
||||||
|
|
||||||
cacheCfg := getCacheOptions(v, l)
|
cacheCfg := getCacheOptions(v, l)
|
||||||
|
|
||||||
// prepare object layer
|
// prepare object layer
|
||||||
obj = layer.NewLayer(l, conns, cacheCfg)
|
obj = layer.NewLayer(l, conns, cacheCfg, anonKey)
|
||||||
|
|
||||||
// prepare auth center
|
// prepare auth center
|
||||||
ctr = auth.New(conns, key, getAccessBoxCacheConfig(v, l))
|
ctr = auth.New(conns, key, getAccessBoxCacheConfig(v, l))
|
||||||
|
|
Loading…
Reference in a new issue