diff --git a/api/auth/center.go b/api/auth/center.go index 86c011242..1b572a86f 100644 --- a/api/auth/center.go +++ b/api/auth/center.go @@ -15,7 +15,6 @@ import ( v4 "github.com/aws/aws-sdk-go/aws/signer/v4" "github.com/nspcc-dev/neofs-api-go/pkg/object" "github.com/nspcc-dev/neofs-api-go/pkg/token" - "github.com/nspcc-dev/neofs-s3-gw/authmate" "github.com/nspcc-dev/neofs-s3-gw/creds/tokens" "github.com/nspcc-dev/neofs-sdk-go/pkg/pool" "go.uber.org/zap" @@ -98,12 +97,7 @@ func (c *center) Authenticate(r *http.Request) (*token.BearerToken, error) { return nil, fmt.Errorf("could not parse AccessBox address: %s : %w", accessKeyID, err) } - tkn, err := c.cli.GetBearerToken(r.Context(), address) - if err != nil { - return nil, err - } - - secret, err := authmate.BearerToAccessKey(tkn) + tkns, err := c.cli.GetTokens(r.Context(), address) if err != nil { return nil, err } @@ -119,7 +113,7 @@ func (c *center) Authenticate(r *http.Request) (*token.BearerToken, error) { } } - awsCreds := credentials.NewStaticCredentials(accessKeyID, secret, "") + awsCreds := credentials.NewStaticCredentials(accessKeyID, tkns.AccessKey, "") signer := v4.NewSigner(awsCreds) signer.DisableURIPathEscaping = true @@ -133,5 +127,5 @@ func (c *center) Authenticate(r *http.Request) (*token.BearerToken, error) { return nil, errors.New("failed to pass authentication procedure") } - return tkn, nil + return tkns.BearerToken, nil } diff --git a/authmate/authmate.go b/authmate/authmate.go index 58e06375e..2dd7c0ab8 100644 --- a/authmate/authmate.go +++ b/authmate/authmate.go @@ -3,7 +3,6 @@ package authmate import ( "context" "crypto/ecdsa" - "crypto/sha256" "encoding/hex" "encoding/json" "fmt" @@ -141,34 +140,23 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr return err } + gatesData, err := createTokens(options, cid) + if err != nil { + return fmt.Errorf("failed to build bearer token: %w", err) + } + + box, secrets, err := accessbox.PackTokens(gatesData) + if err != nil { + return err + } + oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey) if err != nil { return err } - a.log.Info("prepare eACL table") - bearerRules, err := buildEACLTable(cid, options.EACLRules) - if err != nil { - return fmt.Errorf("failed to build eacl table: %w", err) - } - - bearerTkn, err := buildBearerToken(options.NeoFSKey, bearerRules, options.GatesPublicKeys[0]) - if err != nil { - return fmt.Errorf("failed to build bearer token: %w", err) - } - - sessionTkn, err := createSessionToken(options, oid) - if err != nil { - return fmt.Errorf("failed to create session token: %w", err) - } - - box, ownerKey, err := accessbox.PackTokens(bearerTkn, sessionTkn, options.GatesPublicKeys...) - if err != nil { - return err - } - a.log.Info("store bearer token into NeoFS", - zap.Stringer("owner_tkn", bearerTkn.Issuer())) + zap.Stringer("owner_tkn", oid)) if !options.SessionTkn && len(options.ContextRules) > 0 { _, err := w.Write([]byte("Warning: rules for session token were set but --create-session flag wasn't, " + @@ -179,23 +167,18 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr } address, err := tokens. - New(a.pool, ownerKey). + New(a.pool, secrets.EphemeralKey). Put(ctx, cid, oid, box, options.GatesPublicKeys...) if err != nil { return fmt.Errorf("failed to put bearer token: %w", err) } - secret, err := BearerToAccessKey(bearerTkn) - if err != nil { - return fmt.Errorf("failed to get bearer token secret key: %w", err) - } - accessKeyID := address.ContainerID().String() + "_" + address.ObjectID().String() ir := &issuingResult{ AccessKeyID: accessKeyID, - SecretAccessKey: secret, - OwnerPrivateKey: hex.EncodeToString(crypto.MarshalPrivateKey(ownerKey)), + SecretAccessKey: secrets.AccessKey, + OwnerPrivateKey: hex.EncodeToString(crypto.MarshalPrivateKey(secrets.EphemeralKey)), } enc := json.NewEncoder(w) @@ -212,19 +195,14 @@ func (a *Agent) ObtainSecret(ctx context.Context, w io.Writer, options *ObtainSe return fmt.Errorf("failed to parse secret address: %w", err) } - tkn, err := bearerCreds.GetBearerToken(ctx, address) + tkns, err := bearerCreds.GetTokens(ctx, address) if err != nil { - return fmt.Errorf("failed to get bearer token: %w", err) - } - - secret, err := BearerToAccessKey(tkn) - if err != nil { - return fmt.Errorf("failed to get bearer token secret key: %w", err) + return fmt.Errorf("failed to get tokens: %w", err) } or := &obtainingResult{ - BearerToken: tkn, - SecretAccessKey: secret, + BearerToken: tkns.BearerToken, + SecretAccessKey: tkns.AccessKey, } enc := json.NewEncoder(w) @@ -302,8 +280,8 @@ func buildContext(rules []byte) (*session.ContainerContext, error) { return sessionCtx, nil } -func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, ownerKey *ecdsa.PublicKey) (*token.BearerToken, error) { - oid, err := ownerIDFromNeoFSKey(ownerKey) +func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, gateKey *ecdsa.PublicKey) (*token.BearerToken, error) { + oid, err := ownerIDFromNeoFSKey(gateKey) if err != nil { return nil, err } @@ -316,7 +294,19 @@ func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, ownerKey *ecdsa. return bearerToken, bearerToken.SignToken(key) } -func buildSessionToken(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.ContainerContext) (*session.Token, error) { +func buildBearerTokens(key *ecdsa.PrivateKey, table *eacl.Table, gatesKeys []*ecdsa.PublicKey) ([]*token.BearerToken, error) { + bearerTokens := make([]*token.BearerToken, 0, len(gatesKeys)) + for _, gateKey := range gatesKeys { + tkn, err := buildBearerToken(key, table, gateKey) + if err != nil { + return nil, err + } + bearerTokens = append(bearerTokens, tkn) + } + return bearerTokens, nil +} + +func buildSessionToken(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.ContainerContext, gateKey *ecdsa.PublicKey) (*session.Token, error) { tok := session.NewToken() tok.SetContext(ctx) uid, err := uuid.New().MarshalBinary() @@ -325,30 +315,58 @@ func buildSessionToken(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.Contai } tok.SetID(uid) tok.SetOwnerID(oid) + tok.SetSessionKey(crypto.MarshalPublicKey(gateKey)) return tok, tok.Sign(key) } -func createSessionToken(options *IssueSecretOptions, oid *owner.ID) (*session.Token, error) { +func buildSessionTokens(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.ContainerContext, gatesKeys []*ecdsa.PublicKey) ([]*session.Token, error) { + sessionTokens := make([]*session.Token, 0, len(gatesKeys)) + for _, gateKey := range gatesKeys { + tkn, err := buildSessionToken(key, oid, ctx, gateKey) + if err != nil { + return nil, err + } + sessionTokens = append(sessionTokens, tkn) + } + return sessionTokens, nil +} + +func createTokens(options *IssueSecretOptions, cid *cid.ID) ([]*accessbox.GateData, error) { + gates := make([]*accessbox.GateData, len(options.GatesPublicKeys)) + + table, err := buildEACLTable(cid, options.EACLRules) + if err != nil { + return nil, fmt.Errorf("failed to build eacl table: %w", err) + } + bearerTokens, err := buildBearerTokens(options.NeoFSKey, table, options.GatesPublicKeys) + if err != nil { + return nil, fmt.Errorf("failed to build bearer tokens: %w", err) + } + for i, gateKey := range options.GatesPublicKeys { + gates[i] = accessbox.NewGateData(gateKey, bearerTokens[i]) + } + if options.SessionTkn { sessionRules, err := buildContext(options.ContextRules) if err != nil { return nil, fmt.Errorf("failed to build context for session token: %w", err) } - return buildSessionToken(options.NeoFSKey, oid, sessionRules) - } - return nil, nil -} + oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey) + if err != nil { + return nil, err + } -// BearerToAccessKey returns secret access key generated from given BearerToken. -func BearerToAccessKey(tkn *token.BearerToken) (string, error) { - data, err := tkn.Marshal() - if err != nil { - return "", err + sessionTokens, err := buildSessionTokens(options.NeoFSKey, oid, sessionRules, options.GatesPublicKeys) + if err != nil { + return nil, err + } + for i, sessionToken := range sessionTokens { + gates[i].SessionToken = sessionToken + } } - hash := sha256.Sum256(data) - return hex.EncodeToString(hash[:]), nil + return gates, nil } func ownerIDFromNeoFSKey(key *ecdsa.PublicKey) (*owner.ID, error) { diff --git a/creds/accessbox/accessbox.go b/creds/accessbox/accessbox.go index f235e759b..d2126f72c 100644 --- a/creds/accessbox/accessbox.go +++ b/creds/accessbox/accessbox.go @@ -7,6 +7,7 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/sha256" + "encoding/hex" "fmt" "io" @@ -18,9 +19,23 @@ import ( "google.golang.org/protobuf/proto" ) -type tokenInterface interface { - Marshal(bs ...[]byte) ([]byte, error) - Unmarshal([]byte) error +// GateData represents gate tokens in AccessBox. +type GateData struct { + AccessKey string + BearerToken *token.BearerToken + SessionToken *session.Token + GateKey *ecdsa.PublicKey +} + +// NewGateData returns GateData from provided bearer token and public gate key. +func NewGateData(gateKey *ecdsa.PublicKey, bearerTkn *token.BearerToken) *GateData { + return &GateData{GateKey: gateKey, BearerToken: bearerTkn} +} + +// Secrets represents AccessKey and key to encrypt gate tokens. +type Secrets struct { + AccessKey string + EphemeralKey *ecdsa.PrivateKey } // Marshal returns the wire-format of AccessBox. @@ -35,7 +50,7 @@ func (x *AccessBox) Unmarshal(data []byte) error { // PackTokens adds a bearer and session tokens to BearerTokens and SessionToken lists respectively. // Session token can be nil. -func PackTokens(bearer *token.BearerToken, sess *session.Token, keys ...*ecdsa.PublicKey) (*AccessBox, *ecdsa.PrivateKey, error) { +func PackTokens(gatesData []*GateData) (*AccessBox, *Secrets, error) { box := &AccessBox{} ephemeralKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { @@ -43,98 +58,105 @@ func PackTokens(bearer *token.BearerToken, sess *session.Token, keys ...*ecdsa.P } box.OwnerPublicKey = crypto.MarshalPublicKey(&ephemeralKey.PublicKey) - if err := box.addToken(bearer, &box.BearerTokens, ephemeralKey, keys...); err != nil { - return nil, nil, fmt.Errorf("failed to add bearer token to accessbox: %w", err) - } - if sess != nil { - if err := box.addToken(sess, &box.SessionTokens, ephemeralKey, keys...); err != nil { - return nil, nil, fmt.Errorf("failed to add session token to accessbox: %w", err) - } + secret, err := generateSecret() + if err != nil { + return nil, nil, fmt.Errorf("failed to generate accessKey as hex: %w", err) } - return box, ephemeralKey, err + if err := box.addTokens(gatesData, ephemeralKey, secret); err != nil { + return nil, nil, fmt.Errorf("failed to add tokens to accessbox: %w", err) + } + + return box, &Secrets{hex.EncodeToString(secret), ephemeralKey}, err } -// GetBearerToken returns bearer token from AccessBox. -func (x *AccessBox) GetBearerToken(owner *ecdsa.PrivateKey) (*token.BearerToken, error) { +// GetTokens returns gate tokens from AccessBox. +func (x *AccessBox) GetTokens(owner *ecdsa.PrivateKey) (*GateData, error) { sender := crypto.UnmarshalPublicKey(x.OwnerPublicKey) ownerKey := crypto.MarshalPublicKey(&owner.PublicKey) - for _, data := range x.BearerTokens { - if !bytes.Equal(data.GatePublicKey, ownerKey) { + for _, gate := range x.Gates { + if !bytes.Equal(gate.GatePublicKey, ownerKey) { continue } - tkn := token.NewBearerToken() - if err := decodeToken(data.Token, tkn, owner, sender); err != nil { - return nil, fmt.Errorf("failed to decode bearer token: %w", err) + + gateData, err := decodeGate(gate, owner, sender) + if err != nil { + return nil, fmt.Errorf("failed to decode gate: %w", err) } - return tkn, nil + return gateData, nil } - return nil, fmt.Errorf("no bearer token for key %x was found", ownerKey) + return nil, fmt.Errorf("no gate data for key %x was found", ownerKey) } -// GetSessionToken returns session token from AccessBox. -func (x *AccessBox) GetSessionToken(owner *ecdsa.PrivateKey) (*session.Token, error) { - sender := crypto.UnmarshalPublicKey(x.OwnerPublicKey) - ownerKey := crypto.MarshalPublicKey(&owner.PublicKey) - for _, data := range x.SessionTokens { - if !bytes.Equal(data.GatePublicKey, ownerKey) { - continue - } - tkn := session.NewToken() - - if err := decodeToken(data.Token, tkn, owner, sender); err != nil { - return nil, fmt.Errorf("failed to decode session token: %w", err) - } - return tkn, nil - } - - return nil, fmt.Errorf("no session token for key %x was found", ownerKey) -} - -func (x *AccessBox) addToken(tkn tokenInterface, list *[]*AccessBox_Token, owner *ecdsa.PrivateKey, keys ...*ecdsa.PublicKey) error { - for i, sender := range keys { - data, err := encodeToken(tkn, owner, sender) +func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *ecdsa.PrivateKey, secret []byte) error { + for i, gate := range gatesData { + encBearer, err := gate.BearerToken.Marshal() if err != nil { return fmt.Errorf("%w, sender = %d", err, i) } - *list = append(*list, newToken(data, crypto.MarshalPublicKey(sender))) + var encSession []byte + if gate.SessionToken != nil { + encSession, err = gate.SessionToken.Marshal() + if err != nil { + return fmt.Errorf("%w, sender = %d", err, i) + } + } + + tokens := new(Tokens) + tokens.AccessKey = secret + tokens.BearerToken = encBearer + tokens.SessionToken = encSession + + boxGate, err := encodeGate(ephemeralKey, gate.GateKey, tokens) + if err != nil { + return err + } + x.Gates = append(x.Gates, boxGate) } return nil } -func newToken(data []byte, key []byte) *AccessBox_Token { - res := new(AccessBox_Token) - res.Token = data - res.GatePublicKey = key - return res -} - -func encodeToken(tkn tokenInterface, owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey) ([]byte, error) { - data, err := tkn.Marshal() +func encodeGate(ephemeralKey *ecdsa.PrivateKey, ownerKey *ecdsa.PublicKey, tokens *Tokens) (*AccessBox_Gate, error) { + data, err := proto.Marshal(tokens) if err != nil { return nil, err } - encrypted, err := encrypt(owner, sender, data) + encrypted, err := encrypt(ephemeralKey, ownerKey, data) if err != nil { return nil, err } - return encrypted, nil + + gate := new(AccessBox_Gate) + gate.GatePublicKey = crypto.MarshalPublicKey(ownerKey) + gate.Tokens = encrypted + return gate, nil } -func decodeToken(data []byte, tkn tokenInterface, owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey) error { - decoded, err := decrypt(owner, sender, data) +func decodeGate(gate *AccessBox_Gate, owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey) (*GateData, error) { + data, err := decrypt(owner, sender, gate.Tokens) if err != nil { - return err + return nil, err + } + tokens := new(Tokens) + if err := proto.Unmarshal(data, tokens); err != nil { + return nil, err } - err = tkn.Unmarshal(decoded) - if err != nil { - return err + bearerTkn := token.NewBearerToken() + if err := bearerTkn.Unmarshal(tokens.BearerToken); err != nil { + return nil, err + } + sessionTkn := session.NewToken() + if err := sessionTkn.Unmarshal(tokens.SessionToken); err != nil { + return nil, err } - return nil + gateData := NewGateData(&owner.PublicKey, bearerTkn) + gateData.SessionToken = sessionTkn + gateData.AccessKey = hex.EncodeToString(tokens.AccessKey) + return gateData, nil } func generateShared256(prv *ecdsa.PrivateKey, pub *ecdsa.PublicKey) (sk []byte, err error) { @@ -200,9 +222,11 @@ func getCipher(owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey) (cipher.AEAD, e return nil, err } - aead, err := chacha20poly1305.NewX(key) - if err != nil { - return nil, err - } - return aead, nil + return chacha20poly1305.NewX(key) +} + +func generateSecret() ([]byte, error) { + b := make([]byte, 32) + _, err := io.ReadFull(rand.Reader, b) + return b, err } diff --git a/creds/accessbox/accessbox.pb.go b/creds/accessbox/accessbox.pb.go index b457d8eeb..a0a309120 100644 --- a/creds/accessbox/accessbox.pb.go +++ b/creds/accessbox/accessbox.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.15.8 +// protoc-gen-go v1.26.0 +// protoc v3.6.1 // source: creds/accessbox/accessbox.proto package accessbox import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,18 +20,13 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type AccessBox struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - OwnerPublicKey []byte `protobuf:"bytes,1,opt,name=ownerPublicKey,json=oownerPublicKey,proto3" json:"ownerPublicKey,omitempty"` - BearerTokens []*AccessBox_Token `protobuf:"bytes,2,rep,name=bearerTokens,proto3" json:"bearerTokens,omitempty"` - SessionTokens []*AccessBox_Token `protobuf:"bytes,3,rep,name=sessionTokens,proto3" json:"sessionTokens,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"` } func (x *AccessBox) Reset() { @@ -74,31 +68,25 @@ func (x *AccessBox) GetOwnerPublicKey() []byte { return nil } -func (x *AccessBox) GetBearerTokens() []*AccessBox_Token { +func (x *AccessBox) GetGates() []*AccessBox_Gate { if x != nil { - return x.BearerTokens + return x.Gates } return nil } -func (x *AccessBox) GetSessionTokens() []*AccessBox_Token { - if x != nil { - return x.SessionTokens - } - return nil -} - -type AccessBox_Token struct { +type Tokens struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Token []byte `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` - GatePublicKey []byte `protobuf:"bytes,2,opt,name=gatePublicKey,proto3" json:"gatePublicKey,omitempty"` + AccessKey []byte `protobuf:"bytes,1,opt,name=accessKey,proto3" json:"accessKey,omitempty"` + BearerToken []byte `protobuf:"bytes,2,opt,name=bearerToken,proto3" json:"bearerToken,omitempty"` + SessionToken []byte `protobuf:"bytes,3,opt,name=sessionToken,proto3" json:"sessionToken,omitempty"` } -func (x *AccessBox_Token) Reset() { - *x = AccessBox_Token{} +func (x *Tokens) Reset() { + *x = Tokens{} if protoimpl.UnsafeEnabled { mi := &file_creds_accessbox_accessbox_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -106,13 +94,13 @@ func (x *AccessBox_Token) Reset() { } } -func (x *AccessBox_Token) String() string { +func (x *Tokens) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AccessBox_Token) ProtoMessage() {} +func (*Tokens) ProtoMessage() {} -func (x *AccessBox_Token) ProtoReflect() protoreflect.Message { +func (x *Tokens) ProtoReflect() protoreflect.Message { mi := &file_creds_accessbox_accessbox_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -124,19 +112,81 @@ func (x *AccessBox_Token) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use AccessBox_Token.ProtoReflect.Descriptor instead. -func (*AccessBox_Token) Descriptor() ([]byte, []int) { - return file_creds_accessbox_accessbox_proto_rawDescGZIP(), []int{0, 0} +// Deprecated: Use Tokens.ProtoReflect.Descriptor instead. +func (*Tokens) Descriptor() ([]byte, []int) { + return file_creds_accessbox_accessbox_proto_rawDescGZIP(), []int{1} } -func (x *AccessBox_Token) GetToken() []byte { +func (x *Tokens) GetAccessKey() []byte { if x != nil { - return x.Token + return x.AccessKey } return nil } -func (x *AccessBox_Token) GetGatePublicKey() []byte { +func (x *Tokens) GetBearerToken() []byte { + if x != nil { + return x.BearerToken + } + return nil +} + +func (x *Tokens) GetSessionToken() []byte { + if x != nil { + return x.SessionToken + } + return nil +} + +type AccessBox_Gate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Tokens []byte `protobuf:"bytes,1,opt,name=tokens,proto3" json:"tokens,omitempty"` + GatePublicKey []byte `protobuf:"bytes,2,opt,name=gatePublicKey,proto3" json:"gatePublicKey,omitempty"` +} + +func (x *AccessBox_Gate) Reset() { + *x = AccessBox_Gate{} + if protoimpl.UnsafeEnabled { + mi := &file_creds_accessbox_accessbox_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AccessBox_Gate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccessBox_Gate) ProtoMessage() {} + +func (x *AccessBox_Gate) ProtoReflect() protoreflect.Message { + mi := &file_creds_accessbox_accessbox_proto_msgTypes[2] + 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_Gate.ProtoReflect.Descriptor instead. +func (*AccessBox_Gate) Descriptor() ([]byte, []int) { + return file_creds_accessbox_accessbox_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *AccessBox_Gate) GetTokens() []byte { + if x != nil { + return x.Tokens + } + return nil +} + +func (x *AccessBox_Gate) GetGatePublicKey() []byte { if x != nil { return x.GatePublicKey } @@ -148,27 +198,29 @@ var File_creds_accessbox_accessbox_proto protoreflect.FileDescriptor 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, 0xfb, 0x01, 0x0a, - 0x09, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x6f, 0x78, 0x12, 0x27, 0x0a, 0x0e, 0x6f, 0x77, + 0x6f, 0x12, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x22, 0xaa, 0x01, 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, 0x0f, 0x6f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x12, 0x3e, 0x0a, 0x0c, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x6f, 0x78, 0x2e, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0c, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x73, 0x12, 0x40, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x6f, 0x78, - 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x1a, 0x43, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, - 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 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, 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, + 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, + 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, } var ( @@ -183,19 +235,19 @@ func file_creds_accessbox_accessbox_proto_rawDescGZIP() []byte { return file_creds_accessbox_accessbox_proto_rawDescData } -var file_creds_accessbox_accessbox_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_creds_accessbox_accessbox_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_creds_accessbox_accessbox_proto_goTypes = []interface{}{ - (*AccessBox)(nil), // 0: accessbox.AccessBox - (*AccessBox_Token)(nil), // 1: accessbox.AccessBox.Token + (*AccessBox)(nil), // 0: accessbox.AccessBox + (*Tokens)(nil), // 1: accessbox.Tokens + (*AccessBox_Gate)(nil), // 2: accessbox.AccessBox.Gate } var file_creds_accessbox_accessbox_proto_depIdxs = []int32{ - 1, // 0: accessbox.AccessBox.bearerTokens:type_name -> accessbox.AccessBox.Token - 1, // 1: accessbox.AccessBox.sessionTokens:type_name -> accessbox.AccessBox.Token - 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 + 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 } func init() { file_creds_accessbox_accessbox_proto_init() } @@ -217,7 +269,19 @@ func file_creds_accessbox_accessbox_proto_init() { } } file_creds_accessbox_accessbox_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AccessBox_Token); i { + switch v := v.(*Tokens); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_creds_accessbox_accessbox_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AccessBox_Gate); i { case 0: return &v.state case 1: @@ -235,7 +299,7 @@ func file_creds_accessbox_accessbox_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_creds_accessbox_accessbox_proto_rawDesc, NumEnums: 0, - NumMessages: 2, + NumMessages: 3, NumExtensions: 0, NumServices: 0, }, diff --git a/creds/accessbox/accessbox.proto b/creds/accessbox/accessbox.proto index 8906c9263..5750b8080 100644 --- a/creds/accessbox/accessbox.proto +++ b/creds/accessbox/accessbox.proto @@ -7,13 +7,18 @@ option go_package = "github.com/nspcc-dev/neofs-s3-gw/creds/tokenbox;accessbox"; message AccessBox { - message Token { - bytes token = 1 [json_name = "token"]; + message Gate { + bytes tokens = 1 [json_name = "tokens"]; bytes gatePublicKey = 2 [json_name = "gatePublicKey"]; } - bytes ownerPublicKey = 1 [json_name = "oownerPublicKey"]; - repeated Token bearerTokens = 2 [json_name = "bearerTokens"]; - repeated Token sessionTokens = 3 [json_name = "sessionTokens"]; + bytes ownerPublicKey = 1 [json_name = "ownerPublicKey"]; + repeated Gate gates = 2 [json_name = "gates"]; +} + +message Tokens { + bytes accessKey = 1 [json_name = "accessKey"]; + bytes bearerToken = 2 [json_name = "bearerToken"]; + bytes sessionToken = 3 [json_name = "sessionToken"]; } diff --git a/creds/accessbox/bearer_token_test.go b/creds/accessbox/bearer_token_test.go index 96c1b7267..d9263c721 100644 --- a/creds/accessbox/bearer_token_test.go +++ b/creds/accessbox/bearer_token_test.go @@ -6,12 +6,15 @@ import ( "crypto/rand" "testing" + "github.com/google/uuid" "github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl" + "github.com/nspcc-dev/neofs-api-go/pkg/session" "github.com/nspcc-dev/neofs-api-go/pkg/token" + crypto "github.com/nspcc-dev/neofs-crypto" "github.com/stretchr/testify/require" ) -func Test_tokens_encode_decode(t *testing.T) { +func Test_tokens_encrypt_decrypt(t *testing.T) { var ( tkn = token.NewBearerToken() tkn2 = token.NewBearerToken() @@ -25,10 +28,16 @@ func Test_tokens_encode_decode(t *testing.T) { tkn.SetEACLTable(eacl.NewTable()) require.NoError(t, tkn.SignToken(sec)) - data, err := encodeToken(tkn, cred, &cred.PublicKey) + rawTkn, err := tkn.Marshal() require.NoError(t, err) - err = decodeToken(data, tkn2, cred, &cred.PublicKey) + data, err := encrypt(cred, &cred.PublicKey, rawTkn) + require.NoError(t, err) + + rawTkn2, err := decrypt(cred, &cred.PublicKey, data) + require.NoError(t, err) + + err = tkn2.Unmarshal(rawTkn2) require.NoError(t, err) require.Equal(t, tkn, tkn2) @@ -50,7 +59,8 @@ func Test_bearer_token_in_access_box(t *testing.T) { tkn.SetEACLTable(eacl.NewTable()) require.NoError(t, tkn.SignToken(sec)) - box, _, err = PackTokens(tkn, nil, &cred.PublicKey) + gate := NewGateData(&cred.PublicKey, tkn) + box, _, err = PackTokens([]*GateData{gate}) require.NoError(t, err) data, err := box.Marshal() @@ -59,10 +69,48 @@ func Test_bearer_token_in_access_box(t *testing.T) { err = box2.Unmarshal(data) require.NoError(t, err) - tkn2, err := box2.GetBearerToken(cred) + tkns, err := box2.GetTokens(cred) require.NoError(t, err) - require.Equal(t, tkn, tkn2) + require.Equal(t, tkn, tkns.BearerToken) +} + +func Test_session_token_in_access_box(t *testing.T) { + var ( + box *AccessBox + box2 AccessBox + tkn = session.NewToken() + ) + + sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + require.NoError(t, err) + + cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + require.NoError(t, err) + + tok := session.NewToken() + tok.SetContext(session.NewContainerContext()) + uid, err := uuid.New().MarshalBinary() + require.NoError(t, err) + tok.SetID(uid) + tok.SetSessionKey(crypto.MarshalPublicKey(&sec.PublicKey)) + require.NoError(t, tkn.Sign(sec)) + + gate := NewGateData(&cred.PublicKey, token.NewBearerToken()) + gate.SessionToken = tkn + box, _, err = PackTokens([]*GateData{gate}) + require.NoError(t, err) + + data, err := box.Marshal() + require.NoError(t, err) + + err = box2.Unmarshal(data) + require.NoError(t, err) + + tkns, err := box2.GetTokens(cred) + require.NoError(t, err) + + require.Equal(t, tkn, tkns.SessionToken) } func Test_accessbox_multiple_keys(t *testing.T) { @@ -78,25 +126,25 @@ func Test_accessbox_multiple_keys(t *testing.T) { require.NoError(t, tkn.SignToken(sec)) count := 10 - pubs := make([]*ecdsa.PublicKey, 0, count) + gates := make([]*GateData, 0, count) keys := make([]*ecdsa.PrivateKey, 0, count) { // generate keys for i := 0; i < count; i++ { cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err) - pubs = append(pubs, &cred.PublicKey) + gates = append(gates, NewGateData(&cred.PublicKey, tkn)) keys = append(keys, cred) } } - box, _, err = PackTokens(tkn, nil, pubs...) + box, _, err = PackTokens(gates) require.NoError(t, err) for i, k := range keys { - tkn2, err := box.GetBearerToken(k) + tkns, err := box.GetTokens(k) require.NoError(t, err, "key #%d: %s failed", i, k) - require.Equal(t, tkn2, tkn) + require.Equal(t, tkns.BearerToken, tkn) } } @@ -118,9 +166,10 @@ func Test_unknown_key(t *testing.T) { tkn.SetEACLTable(eacl.NewTable()) require.NoError(t, tkn.SignToken(sec)) - box, _, err = PackTokens(tkn, nil, &cred.PublicKey) + gate := NewGateData(&cred.PublicKey, tkn) + box, _, err = PackTokens([]*GateData{gate}) require.NoError(t, err) - _, err = box.GetBearerToken(wrongCred) + _, err = box.GetTokens(wrongCred) require.Error(t, err) } diff --git a/creds/tokens/credentials.go b/creds/tokens/credentials.go index ac69807cf..4b4b7ee75 100644 --- a/creds/tokens/credentials.go +++ b/creds/tokens/credentials.go @@ -13,8 +13,6 @@ import ( cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id" "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/session" - "github.com/nspcc-dev/neofs-api-go/pkg/token" "github.com/nspcc-dev/neofs-s3-gw/creds/accessbox" "github.com/nspcc-dev/neofs-sdk-go/pkg/pool" ) @@ -22,8 +20,7 @@ import ( type ( // Credentials is a bearer token get/put interface. Credentials interface { - GetBearerToken(context.Context, *object.Address) (*token.BearerToken, error) - GetSessionToken(context.Context, *object.Address) (*session.Token, error) + GetTokens(context.Context, *object.Address) (*accessbox.GateData, error) Put(context.Context, *cid.ID, *owner.ID, *accessbox.AccessBox, ...*ecdsa.PublicKey) (*object.Address, error) } @@ -62,31 +59,13 @@ func (c *cred) releaseBuffer(buf *bytes.Buffer) { bufferPool.Put(buf) } -func (c *cred) GetBearerToken(ctx context.Context, address *object.Address) (*token.BearerToken, error) { +func (c *cred) GetTokens(ctx context.Context, address *object.Address) (*accessbox.GateData, error) { box, err := c.getAccessBox(ctx, address) if err != nil { return nil, err } - tkn, err := box.GetBearerToken(c.key) - if err != nil { - return nil, err - } - return tkn, nil -} - -func (c *cred) GetSessionToken(ctx context.Context, address *object.Address) (*session.Token, error) { - box, err := c.getAccessBox(ctx, address) - if err != nil { - return nil, err - } - - tkn, err := box.GetSessionToken(c.key) - if err != nil { - return nil, err - } - - return tkn, nil + return box.GetTokens(c.key) } func (c *cred) getAccessBox(ctx context.Context, address *object.Address) (*accessbox.AccessBox, error) {