forked from TrueCloudLab/frostfs-s3-gw
[#83] Added sessionKey to token
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
d1594b586e
commit
81408dcc1c
3 changed files with 112 additions and 43 deletions
|
@ -140,28 +140,17 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey)
|
gatesData, err := createTokens(options, cid)
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionTkn, err := createSessionToken(options, oid)
|
box, secrets, err := accessbox.PackTokens(gatesData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create session token: %w", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
box, secrets, err := accessbox.PackTokens(gatesData, sessionTkn)
|
oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -291,8 +280,8 @@ func buildContext(rules []byte) (*session.ContainerContext, error) {
|
||||||
return sessionCtx, nil
|
return sessionCtx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, ownerKey *ecdsa.PublicKey) (*token.BearerToken, error) {
|
func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, gateKey *ecdsa.PublicKey) (*token.BearerToken, error) {
|
||||||
oid, err := ownerIDFromNeoFSKey(ownerKey)
|
oid, err := ownerIDFromNeoFSKey(gateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -305,19 +294,19 @@ 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) {
|
func buildBearerTokens(key *ecdsa.PrivateKey, table *eacl.Table, gatesKeys []*ecdsa.PublicKey) ([]*token.BearerToken, error) {
|
||||||
gatesData := make([]*accessbox.GateData, 0, len(ownerKeys))
|
bearerTokens := make([]*token.BearerToken, 0, len(gatesKeys))
|
||||||
for _, ownerKey := range ownerKeys {
|
for _, gateKey := range gatesKeys {
|
||||||
tkn, err := buildBearerToken(key, table, ownerKey)
|
tkn, err := buildBearerToken(key, table, gateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
gatesData = append(gatesData, accessbox.NewGateData(tkn, ownerKey))
|
bearerTokens = append(bearerTokens, tkn)
|
||||||
}
|
}
|
||||||
return gatesData, nil
|
return bearerTokens, 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, gateKey *ecdsa.PublicKey) (*session.Token, error) {
|
||||||
tok := session.NewToken()
|
tok := session.NewToken()
|
||||||
tok.SetContext(ctx)
|
tok.SetContext(ctx)
|
||||||
uid, err := uuid.New().MarshalBinary()
|
uid, err := uuid.New().MarshalBinary()
|
||||||
|
@ -326,19 +315,58 @@ func buildSessionToken(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.Contai
|
||||||
}
|
}
|
||||||
tok.SetID(uid)
|
tok.SetID(uid)
|
||||||
tok.SetOwnerID(oid)
|
tok.SetOwnerID(oid)
|
||||||
|
tok.SetSessionKey(crypto.MarshalPublicKey(gateKey))
|
||||||
|
|
||||||
return tok, tok.Sign(key)
|
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 {
|
if options.SessionTkn {
|
||||||
sessionRules, err := buildContext(options.ContextRules)
|
sessionRules, err := buildContext(options.ContextRules)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to build context for session token: %w", err)
|
return nil, fmt.Errorf("failed to build context for session token: %w", err)
|
||||||
}
|
}
|
||||||
return buildSessionToken(options.NeoFSKey, oid, sessionRules)
|
oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, nil
|
|
||||||
|
sessionTokens, err := buildSessionTokens(options.NeoFSKey, oid, sessionRules, options.GatesPublicKeys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i, sessionToken := range sessionTokens {
|
||||||
|
gates[i].SessionToken = sessionToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gates, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ownerIDFromNeoFSKey(key *ecdsa.PublicKey) (*owner.ID, error) {
|
func ownerIDFromNeoFSKey(key *ecdsa.PublicKey) (*owner.ID, error) {
|
||||||
|
|
|
@ -24,12 +24,12 @@ type GateData struct {
|
||||||
AccessKey string
|
AccessKey string
|
||||||
BearerToken *token.BearerToken
|
BearerToken *token.BearerToken
|
||||||
SessionToken *session.Token
|
SessionToken *session.Token
|
||||||
OwnerKey *ecdsa.PublicKey
|
GateKey *ecdsa.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGateData returns GateData from provided bearer token and public key.
|
// NewGateData returns GateData from provided bearer token and public gate key.
|
||||||
func NewGateData(bearerTkn *token.BearerToken, ownerKey *ecdsa.PublicKey) *GateData {
|
func NewGateData(gateKey *ecdsa.PublicKey, bearerTkn *token.BearerToken) *GateData {
|
||||||
return &GateData{BearerToken: bearerTkn, OwnerKey: ownerKey}
|
return &GateData{GateKey: gateKey, BearerToken: bearerTkn}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Secrets represents AccessKey and key to encrypt gate tokens.
|
// Secrets represents AccessKey and key to encrypt gate tokens.
|
||||||
|
@ -50,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(gatesData []*GateData, sess *session.Token) (*AccessBox, *Secrets, error) {
|
func PackTokens(gatesData []*GateData) (*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 {
|
||||||
|
@ -63,7 +63,7 @@ func PackTokens(gatesData []*GateData, sess *session.Token) (*AccessBox, *Secret
|
||||||
return nil, nil, fmt.Errorf("failed to generate accessKey as hex: %w", err)
|
return nil, nil, fmt.Errorf("failed to generate accessKey as hex: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := box.addTokens(gatesData, ephemeralKey, sess, secret); err != nil {
|
if err := box.addTokens(gatesData, ephemeralKey, secret); err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to add tokens to accessbox: %w", err)
|
return nil, nil, fmt.Errorf("failed to add tokens to accessbox: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,14 +89,14 @@ func (x *AccessBox) GetTokens(owner *ecdsa.PrivateKey) (*GateData, error) {
|
||||||
return nil, fmt.Errorf("no gate data for key %x was found", ownerKey)
|
return nil, fmt.Errorf("no gate data for key %x was found", ownerKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *ecdsa.PrivateKey, sess *session.Token, secret []byte) error {
|
func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *ecdsa.PrivateKey, secret []byte) error {
|
||||||
for i, gate := range gatesData {
|
for i, gate := range gatesData {
|
||||||
encBearer, err := gate.BearerToken.Marshal()
|
encBearer, err := gate.BearerToken.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w, sender = %d", err, i)
|
return fmt.Errorf("%w, sender = %d", err, i)
|
||||||
}
|
}
|
||||||
var encSession []byte
|
var encSession []byte
|
||||||
if sess != nil {
|
if gate.SessionToken != nil {
|
||||||
encSession, err = gate.SessionToken.Marshal()
|
encSession, err = gate.SessionToken.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w, sender = %d", err, i)
|
return fmt.Errorf("%w, sender = %d", err, i)
|
||||||
|
@ -108,7 +108,7 @@ func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *ecdsa.Private
|
||||||
tokens.BearerToken = encBearer
|
tokens.BearerToken = encBearer
|
||||||
tokens.SessionToken = encSession
|
tokens.SessionToken = encSession
|
||||||
|
|
||||||
boxGate, err := encodeGate(ephemeralKey, gate.OwnerKey, tokens)
|
boxGate, err := encodeGate(ephemeralKey, gate.GateKey, tokens)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ func decodeGate(gate *AccessBox_Gate, owner *ecdsa.PrivateKey, sender *ecdsa.Pub
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
gateData := NewGateData(bearerTkn, &owner.PublicKey)
|
gateData := NewGateData(&owner.PublicKey, bearerTkn)
|
||||||
gateData.SessionToken = sessionTkn
|
gateData.SessionToken = sessionTkn
|
||||||
gateData.AccessKey = hex.EncodeToString(tokens.AccessKey)
|
gateData.AccessKey = hex.EncodeToString(tokens.AccessKey)
|
||||||
return gateData, nil
|
return gateData, nil
|
||||||
|
|
|
@ -6,8 +6,11 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/pkg/session"
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/token"
|
"github.com/nspcc-dev/neofs-api-go/pkg/token"
|
||||||
|
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -56,8 +59,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))
|
||||||
|
|
||||||
gate := NewGateData(tkn, &cred.PublicKey)
|
gate := NewGateData(&cred.PublicKey, tkn)
|
||||||
box, _, err = PackTokens([]*GateData{gate}, nil)
|
box, _, err = PackTokens([]*GateData{gate})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
data, err := box.Marshal()
|
data, err := box.Marshal()
|
||||||
|
@ -72,6 +75,44 @@ func Test_bearer_token_in_access_box(t *testing.T) {
|
||||||
require.Equal(t, tkn, tkns.BearerToken)
|
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) {
|
func Test_accessbox_multiple_keys(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
box *AccessBox
|
box *AccessBox
|
||||||
|
@ -92,12 +133,12 @@ func Test_accessbox_multiple_keys(t *testing.T) {
|
||||||
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
gates = append(gates, NewGateData(tkn, &cred.PublicKey))
|
gates = append(gates, NewGateData(&cred.PublicKey, tkn))
|
||||||
keys = append(keys, cred)
|
keys = append(keys, cred)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
box, _, err = PackTokens(gates, nil)
|
box, _, err = PackTokens(gates)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for i, k := range keys {
|
for i, k := range keys {
|
||||||
|
@ -125,8 +166,8 @@ 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))
|
||||||
|
|
||||||
gate := NewGateData(tkn, &cred.PublicKey)
|
gate := NewGateData(&cred.PublicKey, tkn)
|
||||||
box, _, err = PackTokens([]*GateData{gate}, nil)
|
box, _, err = PackTokens([]*GateData{gate})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = box.GetTokens(wrongCred)
|
_, err = box.GetTokens(wrongCred)
|
||||||
|
|
Loading…
Reference in a new issue