[#89] Add placement policy

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2021-07-16 15:35:07 +03:00
parent 739c04a274
commit 1fbd192bd7
11 changed files with 386 additions and 123 deletions

View file

@ -26,7 +26,7 @@ var authorizationFieldRegexp = regexp.MustCompile(`AWS4-HMAC-SHA256 Credential=(
type (
// Center is a user authentication interface.
Center interface {
Authenticate(request *http.Request) (*accessbox.GateData, error)
Authenticate(request *http.Request) (*accessbox.Box, error)
}
center struct {
@ -64,7 +64,7 @@ func New(conns pool.Pool, key *keys.PrivateKey) Center {
}
}
func (c *center) Authenticate(r *http.Request) (*accessbox.GateData, error) {
func (c *center) Authenticate(r *http.Request) (*accessbox.Box, error) {
queryValues := r.URL.Query()
if queryValues.Get("X-Amz-Algorithm") == "AWS4-HMAC-SHA256" {
return nil, errors.New("pre-signed form of request is not supported")
@ -98,7 +98,7 @@ func (c *center) Authenticate(r *http.Request) (*accessbox.GateData, error) {
return nil, fmt.Errorf("could not parse AccessBox address: %s : %w", accessKeyID, err)
}
tkns, err := c.cli.GetTokens(r.Context(), address)
box, err := c.cli.GetBox(r.Context(), address)
if err != nil {
return nil, err
}
@ -114,7 +114,7 @@ func (c *center) Authenticate(r *http.Request) (*accessbox.GateData, error) {
}
}
awsCreds := credentials.NewStaticCredentials(accessKeyID, tkns.AccessKey, "")
awsCreds := credentials.NewStaticCredentials(accessKeyID, box.Gate.AccessKey, "")
signer := v4.NewSigner(awsCreds)
signer.DisableURIPathEscaping = true
@ -128,5 +128,5 @@ func (c *center) Authenticate(r *http.Request) (*accessbox.GateData, error) {
return nil, errors.New("failed to pass authentication procedure")
}
return tkns, nil
return box, nil
}

View file

@ -1,6 +1,8 @@
package handler
import (
"context"
"encoding/xml"
"fmt"
"net/http"
"strconv"
@ -11,6 +13,7 @@ import (
"github.com/nspcc-dev/neofs-node/pkg/policy"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
"go.uber.org/zap"
)
@ -24,6 +27,11 @@ const (
publicBasicRule = 0x0FFFFFFF
)
type createBucketParams struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CreateBucketConfiguration" json:"-"`
LocationConstraint string
}
func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
var (
err error
@ -90,43 +98,41 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
}
if err != nil {
h.log.Error("could not parse basic ACL",
zap.String("request_id", rid),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrBadRequest).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusBadRequest,
}, r.URL)
h.writeError(w, r, "could not parse basic ACL", rid, err)
return
}
p.Policy, err = policy.Parse(defaultPolicy)
createParams, err := parseLocationConstraint(r)
if err != nil {
h.log.Error("could not parse policy",
zap.String("request_id", rid),
zap.Error(err))
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrBadRequest).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusBadRequest,
}, r.URL)
h.writeError(w, r, "could not parse body", rid, err)
return
}
cid, err := h.obj.CreateBucket(r.Context(), &p)
boxData, err := getBoxData(r.Context())
if err != nil {
h.log.Error("could not create bucket",
zap.String("request_id", rid),
zap.Error(err))
h.writeError(w, r, "could get boxData", rid, err)
return
}
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: api.GetAPIError(api.ErrInternalError).Code,
Description: err.Error(),
HTTPStatusCode: http.StatusInternalServerError,
}, r.URL)
if createParams.LocationConstraint != "" {
for _, placementPolicy := range boxData.Policies {
if placementPolicy.LocationConstraint == createParams.LocationConstraint {
p.Policy = placementPolicy.Policy
break
}
}
}
if p.Policy == nil {
p.Policy, err = policy.Parse(defaultPolicy)
if err != nil {
h.writeError(w, r, "could not parse policy", rid, err)
return
}
}
cid, err := h.obj.CreateBucket(r.Context(), &p, boxData)
if err != nil {
h.writeError(w, r, "could not create bucket", rid, err)
return
}
@ -136,6 +142,18 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
api.WriteSuccessResponseHeadersOnly(w)
}
func parseLocationConstraint(r *http.Request) (*createBucketParams, error) {
if r.ContentLength == 0 {
return new(createBucketParams), nil
}
params := new(createBucketParams)
if err := xml.NewDecoder(r.Body).Decode(params); err != nil {
return nil, err
}
return params, nil
}
func parseBasicACL(basicACL string) (uint32, error) {
switch basicACL {
case basicACLPublic:
@ -155,3 +173,22 @@ func parseBasicACL(basicACL string) (uint32, error) {
return uint32(value), nil
}
}
func (h *handler) writeError(w http.ResponseWriter, r *http.Request, msg, rid string, err error) {
h.log.Error(msg, zap.String("request_id", rid), zap.Error(err))
api.WriteErrorResponse(r.Context(), w, err, r.URL)
}
func getBoxData(ctx context.Context) (*accessbox.Box, error) {
var boxData *accessbox.Box
data, ok := ctx.Value(api.BoxData).(*accessbox.Box)
if !ok || data == nil {
return nil, fmt.Errorf("couldn't get box data from context")
}
boxData = data
if boxData.Gate == nil {
boxData.Gate = &accessbox.GateData{}
}
return boxData, nil
}

View file

@ -123,21 +123,14 @@ func (n *layer) containerList(ctx context.Context) ([]*BucketInfo, error) {
return list, nil
}
func (n *layer) createContainer(ctx context.Context, p *CreateBucketParams) (*cid.ID, error) {
func (n *layer) createContainer(ctx context.Context, p *CreateBucketParams, boxData *accessbox.Box) (*cid.ID, error) {
cnr := container.New(
container.WithPolicy(p.Policy),
container.WithCustomBasicACL(p.ACL),
container.WithAttribute(container.AttributeName, p.Name),
container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(time.Now().Unix(), 10)))
var gateData *accessbox.GateData
if data, ok := ctx.Value(api.GateData).(*accessbox.GateData); ok && data != nil {
gateData = data
} else {
return nil, fmt.Errorf("couldn't get gate data from context")
}
cnr.SetSessionToken(gateData.SessionToken)
cnr.SetSessionToken(boxData.Gate.SessionToken)
cnr.SetOwnerID(n.Owner(ctx))
cid, err := n.pool.PutContainer(ctx, cnr)
@ -149,7 +142,7 @@ func (n *layer) createContainer(ctx context.Context, p *CreateBucketParams) (*ci
return nil, err
}
if err := n.setContainerEACL(ctx, cid, gateData.GateKey); err != nil {
if err := n.setContainerEACL(ctx, cid, boxData.Gate.GateKey); err != nil {
return nil, err
}

View file

@ -104,7 +104,7 @@ type (
ListBuckets(ctx context.Context) ([]*BucketInfo, error)
GetBucketInfo(ctx context.Context, name string) (*BucketInfo, error)
CreateBucket(ctx context.Context, p *CreateBucketParams) (*cid.ID, error)
CreateBucket(ctx context.Context, p *CreateBucketParams, boxData *accessbox.Box) (*cid.ID, error)
DeleteBucket(ctx context.Context, p *DeleteBucketParams) error
GetObject(ctx context.Context, p *GetObjectParams) error
@ -150,8 +150,8 @@ func NewLayer(log *zap.Logger, conns pool.Pool) Client {
// Owner returns owner id from BearerToken (context) or from client owner.
func (n *layer) Owner(ctx context.Context) *owner.ID {
if data, ok := ctx.Value(api.GateData).(*accessbox.GateData); ok && data != nil {
return data.BearerToken.Issuer()
if data, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && data != nil && data.Gate != nil {
return data.Gate.BearerToken.Issuer()
}
return n.pool.OwnerID()
@ -159,8 +159,8 @@ func (n *layer) Owner(ctx context.Context) *owner.ID {
// BearerOpt returns client.WithBearer call option with token from context or with nil token.
func (n *layer) BearerOpt(ctx context.Context) client.CallOption {
if data, ok := ctx.Value(api.GateData).(*accessbox.GateData); ok && data != nil {
return client.WithBearer(data.BearerToken)
if data, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && data != nil && data.Gate != nil {
return client.WithBearer(data.Gate.BearerToken)
}
return client.WithBearer(nil)
@ -168,8 +168,8 @@ func (n *layer) BearerOpt(ctx context.Context) client.CallOption {
// SessionOpt returns client.WithSession call option with token from context or with nil token.
func (n *layer) SessionOpt(ctx context.Context) client.CallOption {
if data, ok := ctx.Value(api.GateData).(*accessbox.GateData); ok && data != nil {
return client.WithSession(data.SessionToken)
if data, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && data != nil && data.Gate != nil {
return client.WithSession(data.Gate.SessionToken)
}
return client.WithSession(nil)
@ -498,11 +498,11 @@ func (n *layer) DeleteObjects(ctx context.Context, bucket string, objects []stri
return errs
}
func (n *layer) CreateBucket(ctx context.Context, p *CreateBucketParams) (*cid.ID, error) {
func (n *layer) CreateBucket(ctx context.Context, p *CreateBucketParams, boxData *accessbox.Box) (*cid.ID, error) {
_, err := n.GetBucketInfo(ctx, p.Name)
if err != nil {
if errors.Is(err, ErrBucketNotFound) {
return n.createContainer(ctx, p)
return n.createContainer(ctx, p, boxData)
}
return nil, err
}

View file

@ -12,15 +12,15 @@ import (
// KeyWrapper is wrapper for context keys.
type KeyWrapper string
// GateData is an ID used to store GateData in a context.
var GateData = KeyWrapper("__context_gate_data_key")
// BoxData is an ID used to store accessbox.Box in a context.
var BoxData = KeyWrapper("__context_box_key")
// AttachUserAuth adds user authentication via center to router using log for logging.
func AttachUserAuth(router *mux.Router, center auth.Center, log *zap.Logger) {
router.Use(func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var ctx context.Context
tokens, err := center.Authenticate(r)
box, err := center.Authenticate(r)
if err != nil {
if err == auth.ErrNoAuthorizationHeader {
log.Debug("couldn't receive bearer token, using neofs-key")
@ -31,7 +31,7 @@ func AttachUserAuth(router *mux.Router, center auth.Center, log *zap.Logger) {
return
}
} else {
ctx = context.WithValue(r.Context(), GateData, tokens)
ctx = context.WithValue(r.Context(), BoxData, box)
}
h.ServeHTTP(w, r.WithContext(ctx))

View file

@ -44,6 +44,9 @@ func New(log *zap.Logger, conns pool.Pool) *Agent {
}
type (
// ContainerPolicies contains mapping of aws LocationConstraint to neofs PlacementPolicy.
ContainerPolicies map[string]string
// IssueSecretOptions contains options for passing to Agent.IssueSecret method.
IssueSecretOptions struct {
ContainerID *cid.ID
@ -54,6 +57,7 @@ type (
ContextRules []byte
SessionTkn bool
Lifetime uint64
ContainerPolicies ContainerPolicies
}
// ObtainSecretOptions contains options for passing to Agent.ObtainSecret method.
@ -121,6 +125,45 @@ func (a *Agent) getCurrentEpoch(ctx context.Context) (uint64, error) {
}
}
func checkPolicy(policyString string) (*netmap.PlacementPolicy, error) {
result, err := policy.Parse(policyString)
if err == nil {
return result, nil
}
result = netmap.NewPlacementPolicy()
if err = result.UnmarshalJSON([]byte(policyString)); err == nil {
return result, nil
}
return nil, fmt.Errorf("can't parse placement policy")
}
func preparePolicy(policy ContainerPolicies) ([]*accessbox.AccessBox_ContainerPolicy, error) {
if policy == nil {
return nil, nil
}
var result []*accessbox.AccessBox_ContainerPolicy
for locationConstraint, placementPolicy := range policy {
parsedPolicy, err := checkPolicy(placementPolicy)
if err != nil {
return nil, err
}
marshaled, err := parsedPolicy.Marshal()
if err != nil {
return nil, fmt.Errorf("can't marshal placement policy: %w", err)
}
result = append(result, &accessbox.AccessBox_ContainerPolicy{
LocationConstraint: locationConstraint,
Policy: marshaled,
})
}
return result, nil
}
// IssueSecret creates an auth token, puts it in the NeoFS network and writes to io.Writer a new secret access key.
func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecretOptions) error {
var (
@ -130,6 +173,11 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
lifetime lifetimeOptions
)
policies, err := preparePolicy(options.ContainerPolicies)
if err != nil {
return err
}
lifetime.Iat, err = a.getCurrentEpoch(ctx)
if err != nil {
return err
@ -156,6 +204,8 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
return err
}
box.ContainerPolicy = policies
oid, err := ownerIDFromNeoFSKey(options.NeoFSKey.PublicKey())
if err != nil {
return err
@ -201,14 +251,14 @@ func (a *Agent) ObtainSecret(ctx context.Context, w io.Writer, options *ObtainSe
return fmt.Errorf("failed to parse secret address: %w", err)
}
tkns, err := bearerCreds.GetTokens(ctx, address)
box, err := bearerCreds.GetBox(ctx, address)
if err != nil {
return fmt.Errorf("failed to get tokens: %w", err)
}
or := &obtainingResult{
BearerToken: tkns.BearerToken,
SecretAccessKey: tkns.AccessKey,
BearerToken: box.Gate.BearerToken,
SecretAccessKey: box.Gate.AccessKey,
}
enc := json.NewEncoder(w)

View file

@ -3,6 +3,7 @@ package main
import (
"context"
"crypto/ecdsa"
"encoding/json"
"fmt"
"os"
"os/signal"
@ -45,6 +46,7 @@ var (
logDebugEnabledFlag bool
sessionTokenFlag bool
lifetimeFlag uint64
containerPolicies string
)
const (
@ -201,6 +203,12 @@ func issueSecret() *cli.Command {
Destination: &lifetimeFlag,
Value: defaultLifetime,
},
&cli.StringFlag{
Name: "container-policy",
Usage: "mapping AWS storage class to NeoFS storage policy as plain json string or path to json file",
Required: false,
Destination: &containerPolicies,
},
},
Action: func(c *cli.Context) error {
ctx, log := prepare()
@ -241,6 +249,11 @@ func issueSecret() *cli.Command {
return cli.Exit(fmt.Sprintf("lifetime must be at least 1, current value: %d", lifetimeFlag), 5)
}
policies, err := parsePolicies(containerPolicies)
if err != nil {
return cli.Exit(fmt.Sprintf("couldn't parse container policy: %s", err.Error()), 6)
}
issueSecretOptions := &authmate.IssueSecretOptions{
ContainerID: containerID,
ContainerFriendlyName: containerFriendlyName,
@ -248,6 +261,7 @@ func issueSecret() *cli.Command {
GatesPublicKeys: gatesPublicKeys,
EACLRules: getJSONRules(eaclRulesFlag),
ContextRules: getJSONRules(contextRulesFlag),
ContainerPolicies: policies,
SessionTkn: sessionTokenFlag,
Lifetime: lifetimeFlag,
}
@ -261,6 +275,23 @@ func issueSecret() *cli.Command {
}
}
func parsePolicies(val string) (authmate.ContainerPolicies, error) {
if val == "" {
return nil, nil
}
data, err := os.ReadFile(val)
if err != nil {
data = []byte(val)
}
var policies authmate.ContainerPolicies
if err = json.Unmarshal(data, &policies); err != nil {
return nil, err
}
return policies, nil
}
func getJSONRules(val string) []byte {
if data, err := os.ReadFile(val); err == nil {
return data

View file

@ -11,6 +11,7 @@ import (
"io"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
"github.com/nspcc-dev/neofs-api-go/pkg/session"
"github.com/nspcc-dev/neofs-api-go/pkg/token"
"golang.org/x/crypto/chacha20poly1305"
@ -18,6 +19,18 @@ import (
"google.golang.org/protobuf/proto"
)
// Box represents friendly AccessBox.
type Box struct {
Gate *GateData
Policies []*ContainerPolicy
}
// ContainerPolicy represents friendly AccessBox_ContainerPolicy.
type ContainerPolicy struct {
LocationConstraint string
Policy *netmap.PlacementPolicy
}
// GateData represents gate tokens in AccessBox.
type GateData struct {
AccessKey string
@ -91,6 +104,42 @@ func (x *AccessBox) GetTokens(owner *keys.PrivateKey) (*GateData, error) {
return nil, fmt.Errorf("no gate data for key %x was found", ownerKey)
}
// GetPlacementPolicy returns ContainerPolicy from AccessBox.
func (x *AccessBox) GetPlacementPolicy() ([]*ContainerPolicy, error) {
var result []*ContainerPolicy
for _, policy := range x.ContainerPolicy {
placementPolicy := netmap.NewPlacementPolicy()
if err := placementPolicy.Unmarshal(policy.Policy); err != nil {
return nil, err
}
result = append(result, &ContainerPolicy{
LocationConstraint: policy.LocationConstraint,
Policy: placementPolicy,
})
}
return result, nil
}
// GetBox parse AccessBox to Box.
func (x *AccessBox) GetBox(owner *keys.PrivateKey) (*Box, error) {
tokens, err := x.GetTokens(owner)
if err != nil {
return nil, err
}
policy, err := x.GetPlacementPolicy()
if err != nil {
return nil, err
}
return &Box{
Gate: tokens,
Policies: policy,
}, nil
}
func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *keys.PrivateKey, secret []byte) error {
for i, gate := range gatesData {
encBearer, err := gate.BearerToken.Marshal()

View file

@ -7,10 +7,11 @@
package accessbox
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
@ -25,14 +26,15 @@ type AccessBox struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
OwnerPublicKey []byte `protobuf:"bytes,1,opt,name=ownerPublicKey,proto3" json:"ownerPublicKey,omitempty"`
Gates []*AccessBox_Gate `protobuf:"bytes,2,rep,name=gates,proto3" json:"gates,omitempty"`
OwnerPublicKey []byte `protobuf:"bytes,1,opt,name=ownerPublicKey,proto3" json:"ownerPublicKey,omitempty"`
Gates []*AccessBox_Gate `protobuf:"bytes,2,rep,name=gates,proto3" json:"gates,omitempty"`
ContainerPolicy []*AccessBox_ContainerPolicy `protobuf:"bytes,3,rep,name=containerPolicy,proto3" json:"containerPolicy,omitempty"`
}
func (x *AccessBox) Reset() {
*x = AccessBox{}
if protoimpl.UnsafeEnabled {
mi := &file_creds_accessbox_accessbox_proto_msgTypes[0]
mi := &file_accessbox_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -45,7 +47,7 @@ func (x *AccessBox) String() string {
func (*AccessBox) ProtoMessage() {}
func (x *AccessBox) ProtoReflect() protoreflect.Message {
mi := &file_creds_accessbox_accessbox_proto_msgTypes[0]
mi := &file_accessbox_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -58,7 +60,7 @@ func (x *AccessBox) ProtoReflect() protoreflect.Message {
// Deprecated: Use AccessBox.ProtoReflect.Descriptor instead.
func (*AccessBox) Descriptor() ([]byte, []int) {
return file_creds_accessbox_accessbox_proto_rawDescGZIP(), []int{0}
return file_accessbox_proto_rawDescGZIP(), []int{0}
}
func (x *AccessBox) GetOwnerPublicKey() []byte {
@ -75,6 +77,13 @@ func (x *AccessBox) GetGates() []*AccessBox_Gate {
return nil
}
func (x *AccessBox) GetContainerPolicy() []*AccessBox_ContainerPolicy {
if x != nil {
return x.ContainerPolicy
}
return nil
}
type Tokens struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -88,7 +97,7 @@ type Tokens struct {
func (x *Tokens) Reset() {
*x = Tokens{}
if protoimpl.UnsafeEnabled {
mi := &file_creds_accessbox_accessbox_proto_msgTypes[1]
mi := &file_accessbox_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -101,7 +110,7 @@ func (x *Tokens) String() string {
func (*Tokens) ProtoMessage() {}
func (x *Tokens) ProtoReflect() protoreflect.Message {
mi := &file_creds_accessbox_accessbox_proto_msgTypes[1]
mi := &file_accessbox_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -114,7 +123,7 @@ func (x *Tokens) ProtoReflect() protoreflect.Message {
// Deprecated: Use Tokens.ProtoReflect.Descriptor instead.
func (*Tokens) Descriptor() ([]byte, []int) {
return file_creds_accessbox_accessbox_proto_rawDescGZIP(), []int{1}
return file_accessbox_proto_rawDescGZIP(), []int{1}
}
func (x *Tokens) GetAccessKey() []byte {
@ -150,7 +159,7 @@ type AccessBox_Gate struct {
func (x *AccessBox_Gate) Reset() {
*x = AccessBox_Gate{}
if protoimpl.UnsafeEnabled {
mi := &file_creds_accessbox_accessbox_proto_msgTypes[2]
mi := &file_accessbox_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -163,7 +172,7 @@ func (x *AccessBox_Gate) String() string {
func (*AccessBox_Gate) ProtoMessage() {}
func (x *AccessBox_Gate) ProtoReflect() protoreflect.Message {
mi := &file_creds_accessbox_accessbox_proto_msgTypes[2]
mi := &file_accessbox_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -176,7 +185,7 @@ func (x *AccessBox_Gate) ProtoReflect() protoreflect.Message {
// Deprecated: Use AccessBox_Gate.ProtoReflect.Descriptor instead.
func (*AccessBox_Gate) Descriptor() ([]byte, []int) {
return file_creds_accessbox_accessbox_proto_rawDescGZIP(), []int{0, 0}
return file_accessbox_proto_rawDescGZIP(), []int{0, 0}
}
func (x *AccessBox_Gate) GetTokens() []byte {
@ -193,70 +202,137 @@ func (x *AccessBox_Gate) GetGatePublicKey() []byte {
return nil
}
var File_creds_accessbox_accessbox_proto protoreflect.FileDescriptor
type AccessBox_ContainerPolicy struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
var file_creds_accessbox_accessbox_proto_rawDesc = []byte{
0x0a, 0x1f, 0x63, 0x72, 0x65, 0x64, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f,
0x78, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x22, 0xaa, 0x01, 0x0a,
LocationConstraint string `protobuf:"bytes,1,opt,name=locationConstraint,proto3" json:"locationConstraint,omitempty"`
Policy []byte `protobuf:"bytes,2,opt,name=policy,proto3" json:"policy,omitempty"`
}
func (x *AccessBox_ContainerPolicy) Reset() {
*x = AccessBox_ContainerPolicy{}
if protoimpl.UnsafeEnabled {
mi := &file_accessbox_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccessBox_ContainerPolicy) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccessBox_ContainerPolicy) ProtoMessage() {}
func (x *AccessBox_ContainerPolicy) ProtoReflect() protoreflect.Message {
mi := &file_accessbox_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccessBox_ContainerPolicy.ProtoReflect.Descriptor instead.
func (*AccessBox_ContainerPolicy) Descriptor() ([]byte, []int) {
return file_accessbox_proto_rawDescGZIP(), []int{0, 1}
}
func (x *AccessBox_ContainerPolicy) GetLocationConstraint() string {
if x != nil {
return x.LocationConstraint
}
return ""
}
func (x *AccessBox_ContainerPolicy) GetPolicy() []byte {
if x != nil {
return x.Policy
}
return nil
}
var File_accessbox_proto protoreflect.FileDescriptor
var file_accessbox_proto_rawDesc = []byte{
0x0a, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x22, 0xd5, 0x02, 0x0a,
0x09, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x6f, 0x78, 0x12, 0x26, 0x0a, 0x0e, 0x6f, 0x77,
0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x0e, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
0x65, 0x79, 0x12, 0x2f, 0x0a, 0x05, 0x67, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x19, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x41, 0x63,
0x63, 0x65, 0x73, 0x73, 0x42, 0x6f, 0x78, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x52, 0x05, 0x67, 0x61,
0x74, 0x65, 0x73, 0x1a, 0x44, 0x0a, 0x04, 0x47, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74,
0x74, 0x65, 0x73, 0x12, 0x4e, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x61,
0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42,
0x6f, 0x78, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69,
0x63, 0x79, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x6f, 0x6c,
0x69, 0x63, 0x79, 0x1a, 0x44, 0x0a, 0x04, 0x47, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74,
0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x74, 0x6f, 0x6b,
0x65, 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x67, 0x61, 0x74, 0x65,
0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x6c, 0x0a, 0x06, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65,
0x79, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69,
0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6e, 0x73, 0x70, 0x63, 0x63, 0x2d, 0x64, 0x65, 0x76, 0x2f,
0x6e, 0x65, 0x6f, 0x66, 0x73, 0x2d, 0x73, 0x33, 0x2d, 0x67, 0x77, 0x2f, 0x63, 0x72, 0x65, 0x64,
0x73, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x62, 0x6f, 0x78, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73,
0x73, 0x62, 0x6f, 0x78, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x1a, 0x59, 0x0a, 0x0f, 0x43, 0x6f, 0x6e,
0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2e, 0x0a, 0x12,
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69,
0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06,
0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x6f,
0x6c, 0x69, 0x63, 0x79, 0x22, 0x6c, 0x0a, 0x06, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x1c,
0x0a, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b,
0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x0b, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x22,
0x0a, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x6e, 0x73, 0x70, 0x63, 0x63, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x6e, 0x65, 0x6f, 0x66, 0x73,
0x2d, 0x73, 0x33, 0x2d, 0x67, 0x77, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x73, 0x2f, 0x74, 0x6f, 0x6b,
0x65, 0x6e, 0x62, 0x6f, 0x78, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_creds_accessbox_accessbox_proto_rawDescOnce sync.Once
file_creds_accessbox_accessbox_proto_rawDescData = file_creds_accessbox_accessbox_proto_rawDesc
file_accessbox_proto_rawDescOnce sync.Once
file_accessbox_proto_rawDescData = file_accessbox_proto_rawDesc
)
func file_creds_accessbox_accessbox_proto_rawDescGZIP() []byte {
file_creds_accessbox_accessbox_proto_rawDescOnce.Do(func() {
file_creds_accessbox_accessbox_proto_rawDescData = protoimpl.X.CompressGZIP(file_creds_accessbox_accessbox_proto_rawDescData)
func file_accessbox_proto_rawDescGZIP() []byte {
file_accessbox_proto_rawDescOnce.Do(func() {
file_accessbox_proto_rawDescData = protoimpl.X.CompressGZIP(file_accessbox_proto_rawDescData)
})
return file_creds_accessbox_accessbox_proto_rawDescData
return file_accessbox_proto_rawDescData
}
var file_creds_accessbox_accessbox_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_creds_accessbox_accessbox_proto_goTypes = []interface{}{
(*AccessBox)(nil), // 0: accessbox.AccessBox
(*Tokens)(nil), // 1: accessbox.Tokens
(*AccessBox_Gate)(nil), // 2: accessbox.AccessBox.Gate
var file_accessbox_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_accessbox_proto_goTypes = []interface{}{
(*AccessBox)(nil), // 0: accessbox.AccessBox
(*Tokens)(nil), // 1: accessbox.Tokens
(*AccessBox_Gate)(nil), // 2: accessbox.AccessBox.Gate
(*AccessBox_ContainerPolicy)(nil), // 3: accessbox.AccessBox.ContainerPolicy
}
var file_creds_accessbox_accessbox_proto_depIdxs = []int32{
var file_accessbox_proto_depIdxs = []int32{
2, // 0: accessbox.AccessBox.gates:type_name -> accessbox.AccessBox.Gate
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
3, // 1: accessbox.AccessBox.containerPolicy:type_name -> accessbox.AccessBox.ContainerPolicy
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_creds_accessbox_accessbox_proto_init() }
func file_creds_accessbox_accessbox_proto_init() {
if File_creds_accessbox_accessbox_proto != nil {
func init() { file_accessbox_proto_init() }
func file_accessbox_proto_init() {
if File_accessbox_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_creds_accessbox_accessbox_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
file_accessbox_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AccessBox); i {
case 0:
return &v.state
@ -268,7 +344,7 @@ func file_creds_accessbox_accessbox_proto_init() {
return nil
}
}
file_creds_accessbox_accessbox_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
file_accessbox_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Tokens); i {
case 0:
return &v.state
@ -280,7 +356,7 @@ func file_creds_accessbox_accessbox_proto_init() {
return nil
}
}
file_creds_accessbox_accessbox_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
file_accessbox_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AccessBox_Gate); i {
case 0:
return &v.state
@ -292,23 +368,35 @@ func file_creds_accessbox_accessbox_proto_init() {
return nil
}
}
file_accessbox_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AccessBox_ContainerPolicy); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_creds_accessbox_accessbox_proto_rawDesc,
RawDescriptor: file_accessbox_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_creds_accessbox_accessbox_proto_goTypes,
DependencyIndexes: file_creds_accessbox_accessbox_proto_depIdxs,
MessageInfos: file_creds_accessbox_accessbox_proto_msgTypes,
GoTypes: file_accessbox_proto_goTypes,
DependencyIndexes: file_accessbox_proto_depIdxs,
MessageInfos: file_accessbox_proto_msgTypes,
}.Build()
File_creds_accessbox_accessbox_proto = out.File
file_creds_accessbox_accessbox_proto_rawDesc = nil
file_creds_accessbox_accessbox_proto_goTypes = nil
file_creds_accessbox_accessbox_proto_depIdxs = nil
File_accessbox_proto = out.File
file_accessbox_proto_rawDesc = nil
file_accessbox_proto_goTypes = nil
file_accessbox_proto_depIdxs = nil
}

View file

@ -12,8 +12,14 @@ message AccessBox {
bytes gatePublicKey = 2 [json_name = "gatePublicKey"];
}
message ContainerPolicy {
string locationConstraint = 1;
bytes policy = 2;
}
bytes ownerPublicKey = 1 [json_name = "ownerPublicKey"];
repeated Gate gates = 2 [json_name = "gates"];
repeated ContainerPolicy containerPolicy = 3 [json_name = "containerPolicy"];
}
message Tokens {

View file

@ -20,7 +20,7 @@ import (
type (
// Credentials is a bearer token get/put interface.
Credentials interface {
GetTokens(context.Context, *object.Address) (*accessbox.GateData, error)
GetBox(context.Context, *object.Address) (*accessbox.Box, error)
Put(context.Context, *cid.ID, *owner.ID, *accessbox.AccessBox, ...*keys.PublicKey) (*object.Address, error)
}
@ -68,6 +68,15 @@ func (c *cred) GetTokens(ctx context.Context, address *object.Address) (*accessb
return box.GetTokens(c.key)
}
func (c *cred) GetBox(ctx context.Context, address *object.Address) (*accessbox.Box, error) {
box, err := c.getAccessBox(ctx, address)
if err != nil {
return nil, err
}
return box.GetBox(c.key)
}
func (c *cred) getAccessBox(ctx context.Context, address *object.Address) (*accessbox.AccessBox, error) {
var (
box accessbox.AccessBox