[#83] Use multiple bearer tokens

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2021-06-17 19:45:50 +03:00
parent 9060b0a988
commit d1594b586e
7 changed files with 279 additions and 215 deletions

View file

@ -15,7 +15,6 @@ import (
v4 "github.com/aws/aws-sdk-go/aws/signer/v4" 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/object"
"github.com/nspcc-dev/neofs-api-go/pkg/token" "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-s3-gw/creds/tokens"
"github.com/nspcc-dev/neofs-sdk-go/pkg/pool" "github.com/nspcc-dev/neofs-sdk-go/pkg/pool"
"go.uber.org/zap" "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) return nil, fmt.Errorf("could not parse AccessBox address: %s : %w", accessKeyID, err)
} }
tkn, err := c.cli.GetBearerToken(r.Context(), address) tkns, err := c.cli.GetTokens(r.Context(), address)
if err != nil {
return nil, err
}
secret, err := authmate.BearerToAccessKey(tkn)
if err != nil { if err != nil {
return nil, err 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 := v4.NewSigner(awsCreds)
signer.DisableURIPathEscaping = true 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 nil, errors.New("failed to pass authentication procedure")
} }
return tkn, nil return tkns.BearerToken, nil
} }

View file

@ -3,7 +3,6 @@ package authmate
import ( import (
"context" "context"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/sha256"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -152,7 +151,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
return fmt.Errorf("failed to build eacl table: %w", err) return fmt.Errorf("failed to build eacl table: %w", err)
} }
bearerTkn, err := buildBearerToken(options.NeoFSKey, bearerRules, options.GatesPublicKeys[0]) gatesData, err := buildBearerTokens(options.NeoFSKey, bearerRules, options.GatesPublicKeys)
if err != nil { if err != nil {
return fmt.Errorf("failed to build bearer token: %w", err) return fmt.Errorf("failed to build bearer token: %w", err)
} }
@ -162,13 +161,13 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
return fmt.Errorf("failed to create session token: %w", err) return fmt.Errorf("failed to create session token: %w", err)
} }
box, ownerKey, err := accessbox.PackTokens(bearerTkn, sessionTkn, options.GatesPublicKeys...) box, secrets, err := accessbox.PackTokens(gatesData, sessionTkn)
if err != nil { if err != nil {
return err return err
} }
a.log.Info("store bearer token into NeoFS", 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 { if !options.SessionTkn && len(options.ContextRules) > 0 {
_, err := w.Write([]byte("Warning: rules for session token were set but --create-session flag wasn't, " + _, err := w.Write([]byte("Warning: rules for session token were set but --create-session flag wasn't, " +
@ -179,23 +178,18 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
} }
address, err := tokens. address, err := tokens.
New(a.pool, ownerKey). New(a.pool, secrets.EphemeralKey).
Put(ctx, cid, oid, box, options.GatesPublicKeys...) Put(ctx, cid, oid, box, options.GatesPublicKeys...)
if err != nil { if err != nil {
return fmt.Errorf("failed to put bearer token: %w", err) 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() accessKeyID := address.ContainerID().String() + "_" + address.ObjectID().String()
ir := &issuingResult{ ir := &issuingResult{
AccessKeyID: accessKeyID, AccessKeyID: accessKeyID,
SecretAccessKey: secret, SecretAccessKey: secrets.AccessKey,
OwnerPrivateKey: hex.EncodeToString(crypto.MarshalPrivateKey(ownerKey)), OwnerPrivateKey: hex.EncodeToString(crypto.MarshalPrivateKey(secrets.EphemeralKey)),
} }
enc := json.NewEncoder(w) enc := json.NewEncoder(w)
@ -212,19 +206,14 @@ func (a *Agent) ObtainSecret(ctx context.Context, w io.Writer, options *ObtainSe
return fmt.Errorf("failed to parse secret address: %w", err) 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 { if err != nil {
return fmt.Errorf("failed to get bearer token: %w", err) return fmt.Errorf("failed to get tokens: %w", err)
}
secret, err := BearerToAccessKey(tkn)
if err != nil {
return fmt.Errorf("failed to get bearer token secret key: %w", err)
} }
or := &obtainingResult{ or := &obtainingResult{
BearerToken: tkn, BearerToken: tkns.BearerToken,
SecretAccessKey: secret, SecretAccessKey: tkns.AccessKey,
} }
enc := json.NewEncoder(w) enc := json.NewEncoder(w)
@ -316,6 +305,18 @@ func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, ownerKey *ecdsa.
return bearerToken, bearerToken.SignToken(key) return bearerToken, bearerToken.SignToken(key)
} }
func buildBearerTokens(key *ecdsa.PrivateKey, table *eacl.Table, ownerKeys []*ecdsa.PublicKey) ([]*accessbox.GateData, error) {
gatesData := make([]*accessbox.GateData, 0, len(ownerKeys))
for _, ownerKey := range ownerKeys {
tkn, err := buildBearerToken(key, table, ownerKey)
if err != nil {
return nil, err
}
gatesData = append(gatesData, accessbox.NewGateData(tkn, ownerKey))
}
return gatesData, nil
}
func buildSessionToken(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.ContainerContext) (*session.Token, error) { func buildSessionToken(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.ContainerContext) (*session.Token, error) {
tok := session.NewToken() tok := session.NewToken()
tok.SetContext(ctx) tok.SetContext(ctx)
@ -340,17 +341,6 @@ func createSessionToken(options *IssueSecretOptions, oid *owner.ID) (*session.To
return nil, nil return nil, nil
} }
// 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
}
hash := sha256.Sum256(data)
return hex.EncodeToString(hash[:]), nil
}
func ownerIDFromNeoFSKey(key *ecdsa.PublicKey) (*owner.ID, error) { func ownerIDFromNeoFSKey(key *ecdsa.PublicKey) (*owner.ID, error) {
wallet, err := owner.NEO3WalletFromPublicKey(key) wallet, err := owner.NEO3WalletFromPublicKey(key)
if err != nil { if err != nil {

View file

@ -7,6 +7,7 @@ import (
"crypto/elliptic" "crypto/elliptic"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"encoding/hex"
"fmt" "fmt"
"io" "io"
@ -18,9 +19,23 @@ import (
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
type tokenInterface interface { // GateData represents gate tokens in AccessBox.
Marshal(bs ...[]byte) ([]byte, error) type GateData struct {
Unmarshal([]byte) error AccessKey string
BearerToken *token.BearerToken
SessionToken *session.Token
OwnerKey *ecdsa.PublicKey
}
// NewGateData returns GateData from provided bearer token and public key.
func NewGateData(bearerTkn *token.BearerToken, ownerKey *ecdsa.PublicKey) *GateData {
return &GateData{BearerToken: bearerTkn, OwnerKey: ownerKey}
}
// Secrets represents AccessKey and key to encrypt gate tokens.
type Secrets struct {
AccessKey string
EphemeralKey *ecdsa.PrivateKey
} }
// Marshal returns the wire-format of AccessBox. // 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. // PackTokens adds a bearer and session tokens to BearerTokens and SessionToken lists respectively.
// Session token can be nil. // Session token can be nil.
func PackTokens(bearer *token.BearerToken, sess *session.Token, keys ...*ecdsa.PublicKey) (*AccessBox, *ecdsa.PrivateKey, error) { func PackTokens(gatesData []*GateData, sess *session.Token) (*AccessBox, *Secrets, error) {
box := &AccessBox{} box := &AccessBox{}
ephemeralKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) ephemeralKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil { if err != nil {
@ -43,98 +58,105 @@ func PackTokens(bearer *token.BearerToken, sess *session.Token, keys ...*ecdsa.P
} }
box.OwnerPublicKey = crypto.MarshalPublicKey(&ephemeralKey.PublicKey) box.OwnerPublicKey = crypto.MarshalPublicKey(&ephemeralKey.PublicKey)
if err := box.addToken(bearer, &box.BearerTokens, ephemeralKey, keys...); err != nil { secret, err := generateSecret()
return nil, nil, fmt.Errorf("failed to add bearer token to accessbox: %w", err) if err != nil {
} return nil, nil, fmt.Errorf("failed to generate accessKey as hex: %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)
}
} }
return box, ephemeralKey, err if err := box.addTokens(gatesData, ephemeralKey, sess, secret); err != nil {
return nil, nil, fmt.Errorf("failed to add tokens to accessbox: %w", err)
} }
// GetBearerToken returns bearer token from AccessBox. return box, &Secrets{hex.EncodeToString(secret), ephemeralKey}, err
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) sender := crypto.UnmarshalPublicKey(x.OwnerPublicKey)
ownerKey := crypto.MarshalPublicKey(&owner.PublicKey) ownerKey := crypto.MarshalPublicKey(&owner.PublicKey)
for _, data := range x.BearerTokens { for _, gate := range x.Gates {
if !bytes.Equal(data.GatePublicKey, ownerKey) { if !bytes.Equal(gate.GatePublicKey, ownerKey) {
continue continue
} }
tkn := token.NewBearerToken()
if err := decodeToken(data.Token, tkn, owner, sender); err != nil { gateData, err := decodeGate(gate, owner, sender)
return nil, fmt.Errorf("failed to decode bearer token: %w", err) 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) addTokens(gatesData []*GateData, ephemeralKey *ecdsa.PrivateKey, sess *session.Token, secret []byte) error {
func (x *AccessBox) GetSessionToken(owner *ecdsa.PrivateKey) (*session.Token, error) { for i, gate := range gatesData {
sender := crypto.UnmarshalPublicKey(x.OwnerPublicKey) encBearer, err := gate.BearerToken.Marshal()
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)
if err != nil { if err != nil {
return fmt.Errorf("%w, sender = %d", err, i) return fmt.Errorf("%w, sender = %d", err, i)
} }
*list = append(*list, newToken(data, crypto.MarshalPublicKey(sender))) var encSession []byte
if sess != 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.OwnerKey, tokens)
if err != nil {
return err
}
x.Gates = append(x.Gates, boxGate)
} }
return nil return nil
} }
func newToken(data []byte, key []byte) *AccessBox_Token { func encodeGate(ephemeralKey *ecdsa.PrivateKey, ownerKey *ecdsa.PublicKey, tokens *Tokens) (*AccessBox_Gate, error) {
res := new(AccessBox_Token) data, err := proto.Marshal(tokens)
res.Token = data
res.GatePublicKey = key
return res
}
func encodeToken(tkn tokenInterface, owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey) ([]byte, error) {
data, err := tkn.Marshal()
if err != nil { if err != nil {
return nil, err return nil, err
} }
encrypted, err := encrypt(owner, sender, data) encrypted, err := encrypt(ephemeralKey, ownerKey, data)
if err != nil { if err != nil {
return nil, err 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 { func decodeGate(gate *AccessBox_Gate, owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey) (*GateData, error) {
decoded, err := decrypt(owner, sender, data) data, err := decrypt(owner, sender, gate.Tokens)
if err != nil { 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) bearerTkn := token.NewBearerToken()
if err != nil { if err := bearerTkn.Unmarshal(tokens.BearerToken); err != nil {
return err return nil, err
}
sessionTkn := session.NewToken()
if err := sessionTkn.Unmarshal(tokens.SessionToken); err != nil {
return nil, err
} }
return nil gateData := NewGateData(bearerTkn, &owner.PublicKey)
gateData.SessionToken = sessionTkn
gateData.AccessKey = hex.EncodeToString(tokens.AccessKey)
return gateData, nil
} }
func generateShared256(prv *ecdsa.PrivateKey, pub *ecdsa.PublicKey) (sk []byte, err error) { 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 return nil, err
} }
aead, err := chacha20poly1305.NewX(key) return chacha20poly1305.NewX(key)
if err != nil {
return nil, err
} }
return aead, nil
func generateSecret() ([]byte, error) {
b := make([]byte, 32)
_, err := io.ReadFull(rand.Reader, b)
return b, err
} }

View file

@ -1,13 +1,12 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.25.0 // protoc-gen-go v1.26.0
// protoc v3.15.8 // protoc v3.6.1
// source: creds/accessbox/accessbox.proto // source: creds/accessbox/accessbox.proto
package accessbox package accessbox
import ( import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect" reflect "reflect"
@ -21,18 +20,13 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) _ = 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 { type AccessBox struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
OwnerPublicKey []byte `protobuf:"bytes,1,opt,name=ownerPublicKey,json=oownerPublicKey,proto3" json:"ownerPublicKey,omitempty"` OwnerPublicKey []byte `protobuf:"bytes,1,opt,name=ownerPublicKey,proto3" json:"ownerPublicKey,omitempty"`
BearerTokens []*AccessBox_Token `protobuf:"bytes,2,rep,name=bearerTokens,proto3" json:"bearerTokens,omitempty"` Gates []*AccessBox_Gate `protobuf:"bytes,2,rep,name=gates,proto3" json:"gates,omitempty"`
SessionTokens []*AccessBox_Token `protobuf:"bytes,3,rep,name=sessionTokens,proto3" json:"sessionTokens,omitempty"`
} }
func (x *AccessBox) Reset() { func (x *AccessBox) Reset() {
@ -74,31 +68,25 @@ func (x *AccessBox) GetOwnerPublicKey() []byte {
return nil return nil
} }
func (x *AccessBox) GetBearerTokens() []*AccessBox_Token { func (x *AccessBox) GetGates() []*AccessBox_Gate {
if x != nil { if x != nil {
return x.BearerTokens return x.Gates
} }
return nil return nil
} }
func (x *AccessBox) GetSessionTokens() []*AccessBox_Token { type Tokens struct {
if x != nil {
return x.SessionTokens
}
return nil
}
type AccessBox_Token struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Token []byte `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` AccessKey []byte `protobuf:"bytes,1,opt,name=accessKey,proto3" json:"accessKey,omitempty"`
GatePublicKey []byte `protobuf:"bytes,2,opt,name=gatePublicKey,proto3" json:"gatePublicKey,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() { func (x *Tokens) Reset() {
*x = AccessBox_Token{} *x = Tokens{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_creds_accessbox_accessbox_proto_msgTypes[1] mi := &file_creds_accessbox_accessbox_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 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) 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] mi := &file_creds_accessbox_accessbox_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -124,19 +112,81 @@ func (x *AccessBox_Token) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x) return mi.MessageOf(x)
} }
// Deprecated: Use AccessBox_Token.ProtoReflect.Descriptor instead. // Deprecated: Use Tokens.ProtoReflect.Descriptor instead.
func (*AccessBox_Token) Descriptor() ([]byte, []int) { func (*Tokens) Descriptor() ([]byte, []int) {
return file_creds_accessbox_accessbox_proto_rawDescGZIP(), []int{0, 0} return file_creds_accessbox_accessbox_proto_rawDescGZIP(), []int{1}
} }
func (x *AccessBox_Token) GetToken() []byte { func (x *Tokens) GetAccessKey() []byte {
if x != nil { if x != nil {
return x.Token return x.AccessKey
} }
return nil 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 { if x != nil {
return x.GatePublicKey return x.GatePublicKey
} }
@ -148,27 +198,29 @@ var File_creds_accessbox_accessbox_proto protoreflect.FileDescriptor
var file_creds_accessbox_accessbox_proto_rawDesc = []byte{ var file_creds_accessbox_accessbox_proto_rawDesc = []byte{
0x0a, 0x1f, 0x63, 0x72, 0x65, 0x64, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 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, 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, 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, 0x27, 0x0a, 0x0e, 0x6f, 0x77, 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, 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, 0x28, 0x0c, 0x52, 0x0e, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
0x4b, 0x65, 0x79, 0x12, 0x3e, 0x0a, 0x0c, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x05, 0x67, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x65, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x41, 0x63,
0x73, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x6f, 0x78, 0x2e, 0x63, 0x65, 0x73, 0x73, 0x42, 0x6f, 0x78, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x52, 0x05, 0x67, 0x61,
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0c, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x74, 0x65, 0x73, 0x1a, 0x44, 0x0a, 0x04, 0x47, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74,
0x65, 0x6e, 0x73, 0x12, 0x40, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x74, 0x6f, 0x6b,
0x6b, 0x65, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69,
0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x6f, 0x78, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x67, 0x61, 0x74, 0x65,
0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x6c, 0x0a, 0x06, 0x54, 0x6f, 0x6b,
0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x1a, 0x43, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x65, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79,
0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65,
0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x67, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f,
0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x6b, 0x65, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6e, 0x73, 0x70, 0x63, 0x63, 0x2d, 0x64, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69,
0x65, 0x76, 0x2f, 0x6e, 0x65, 0x6f, 0x66, 0x73, 0x2d, 0x73, 0x33, 0x2d, 0x67, 0x77, 0x2f, 0x63, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75,
0x72, 0x65, 0x64, 0x73, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x62, 0x6f, 0x78, 0x3b, 0x61, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6e, 0x73, 0x70, 0x63, 0x63, 0x2d, 0x64, 0x65, 0x76, 0x2f,
0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 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 ( var (
@ -183,19 +235,19 @@ func file_creds_accessbox_accessbox_proto_rawDescGZIP() []byte {
return file_creds_accessbox_accessbox_proto_rawDescData 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{}{ var file_creds_accessbox_accessbox_proto_goTypes = []interface{}{
(*AccessBox)(nil), // 0: accessbox.AccessBox (*AccessBox)(nil), // 0: accessbox.AccessBox
(*AccessBox_Token)(nil), // 1: accessbox.AccessBox.Token (*Tokens)(nil), // 1: accessbox.Tokens
(*AccessBox_Gate)(nil), // 2: accessbox.AccessBox.Gate
} }
var file_creds_accessbox_accessbox_proto_depIdxs = []int32{ var file_creds_accessbox_accessbox_proto_depIdxs = []int32{
1, // 0: accessbox.AccessBox.bearerTokens:type_name -> accessbox.AccessBox.Token 2, // 0: accessbox.AccessBox.gates:type_name -> accessbox.AccessBox.Gate
1, // 1: accessbox.AccessBox.sessionTokens:type_name -> accessbox.AccessBox.Token 1, // [1:1] is the sub-list for method output_type
2, // [2:2] is the sub-list for method output_type 1, // [1:1] is the sub-list for method input_type
2, // [2:2] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee
2, // [2:2] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name
0, // [0:2] is the sub-list for field type_name
} }
func init() { file_creds_accessbox_accessbox_proto_init() } 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{} { 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: case 0:
return &v.state return &v.state
case 1: case 1:
@ -235,7 +299,7 @@ func file_creds_accessbox_accessbox_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_creds_accessbox_accessbox_proto_rawDesc, RawDescriptor: file_creds_accessbox_accessbox_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 2, NumMessages: 3,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View file

@ -7,13 +7,18 @@ option go_package = "github.com/nspcc-dev/neofs-s3-gw/creds/tokenbox;accessbox";
message AccessBox { message AccessBox {
message Token { message Gate {
bytes token = 1 [json_name = "token"]; bytes tokens = 1 [json_name = "tokens"];
bytes gatePublicKey = 2 [json_name = "gatePublicKey"]; bytes gatePublicKey = 2 [json_name = "gatePublicKey"];
} }
bytes ownerPublicKey = 1 [json_name = "oownerPublicKey"]; bytes ownerPublicKey = 1 [json_name = "ownerPublicKey"];
repeated Token bearerTokens = 2 [json_name = "bearerTokens"]; repeated Gate gates = 2 [json_name = "gates"];
repeated Token sessionTokens = 3 [json_name = "sessionTokens"]; }
message Tokens {
bytes accessKey = 1 [json_name = "accessKey"];
bytes bearerToken = 2 [json_name = "bearerToken"];
bytes sessionToken = 3 [json_name = "sessionToken"];
} }

View file

@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func Test_tokens_encode_decode(t *testing.T) { func Test_tokens_encrypt_decrypt(t *testing.T) {
var ( var (
tkn = token.NewBearerToken() tkn = token.NewBearerToken()
tkn2 = token.NewBearerToken() tkn2 = token.NewBearerToken()
@ -25,10 +25,16 @@ func Test_tokens_encode_decode(t *testing.T) {
tkn.SetEACLTable(eacl.NewTable()) tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec)) require.NoError(t, tkn.SignToken(sec))
data, err := encodeToken(tkn, cred, &cred.PublicKey) rawTkn, err := tkn.Marshal()
require.NoError(t, err) 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.NoError(t, err)
require.Equal(t, tkn, tkn2) require.Equal(t, tkn, tkn2)
@ -50,7 +56,8 @@ func Test_bearer_token_in_access_box(t *testing.T) {
tkn.SetEACLTable(eacl.NewTable()) tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec)) require.NoError(t, tkn.SignToken(sec))
box, _, err = PackTokens(tkn, nil, &cred.PublicKey) gate := NewGateData(tkn, &cred.PublicKey)
box, _, err = PackTokens([]*GateData{gate}, nil)
require.NoError(t, err) require.NoError(t, err)
data, err := box.Marshal() data, err := box.Marshal()
@ -59,10 +66,10 @@ func Test_bearer_token_in_access_box(t *testing.T) {
err = box2.Unmarshal(data) err = box2.Unmarshal(data)
require.NoError(t, err) require.NoError(t, err)
tkn2, err := box2.GetBearerToken(cred) tkns, err := box2.GetTokens(cred)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tkn, tkn2) require.Equal(t, tkn, tkns.BearerToken)
} }
func Test_accessbox_multiple_keys(t *testing.T) { func Test_accessbox_multiple_keys(t *testing.T) {
@ -78,25 +85,25 @@ func Test_accessbox_multiple_keys(t *testing.T) {
require.NoError(t, tkn.SignToken(sec)) require.NoError(t, tkn.SignToken(sec))
count := 10 count := 10
pubs := make([]*ecdsa.PublicKey, 0, count) gates := make([]*GateData, 0, count)
keys := make([]*ecdsa.PrivateKey, 0, count) keys := make([]*ecdsa.PrivateKey, 0, count)
{ // generate keys { // generate keys
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
pubs = append(pubs, &cred.PublicKey) gates = append(gates, NewGateData(tkn, &cred.PublicKey))
keys = append(keys, cred) keys = append(keys, cred)
} }
} }
box, _, err = PackTokens(tkn, nil, pubs...) box, _, err = PackTokens(gates, nil)
require.NoError(t, err) require.NoError(t, err)
for i, k := range keys { 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.NoError(t, err, "key #%d: %s failed", i, k)
require.Equal(t, tkn2, tkn) require.Equal(t, tkns.BearerToken, tkn)
} }
} }
@ -118,9 +125,10 @@ func Test_unknown_key(t *testing.T) {
tkn.SetEACLTable(eacl.NewTable()) tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec)) require.NoError(t, tkn.SignToken(sec))
box, _, err = PackTokens(tkn, nil, &cred.PublicKey) gate := NewGateData(tkn, &cred.PublicKey)
box, _, err = PackTokens([]*GateData{gate}, nil)
require.NoError(t, err) require.NoError(t, err)
_, err = box.GetBearerToken(wrongCred) _, err = box.GetTokens(wrongCred)
require.Error(t, err) require.Error(t, err)
} }

View file

@ -13,8 +13,6 @@ import (
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/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-api-go/pkg/token"
"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/pkg/pool" "github.com/nspcc-dev/neofs-sdk-go/pkg/pool"
) )
@ -22,8 +20,7 @@ import (
type ( type (
// Credentials is a bearer token get/put interface. // Credentials is a bearer token get/put interface.
Credentials interface { Credentials interface {
GetBearerToken(context.Context, *object.Address) (*token.BearerToken, error) GetTokens(context.Context, *object.Address) (*accessbox.GateData, error)
GetSessionToken(context.Context, *object.Address) (*session.Token, error)
Put(context.Context, *cid.ID, *owner.ID, *accessbox.AccessBox, ...*ecdsa.PublicKey) (*object.Address, 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) 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) box, err := c.getAccessBox(ctx, address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tkn, err := box.GetBearerToken(c.key) return box.GetTokens(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
} }
func (c *cred) getAccessBox(ctx context.Context, address *object.Address) (*accessbox.AccessBox, error) { func (c *cred) getAccessBox(ctx context.Context, address *object.Address) (*accessbox.AccessBox, error) {