diff --git a/authmate/authmate.go b/authmate/authmate.go index 6266dbb5..2dd7c0ab 100644 --- a/authmate/authmate.go +++ b/authmate/authmate.go @@ -140,28 +140,17 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr 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) - } - - gatesData, err := buildBearerTokens(options.NeoFSKey, bearerRules, options.GatesPublicKeys) + gatesData, err := createTokens(options, cid) if err != nil { return fmt.Errorf("failed to build bearer token: %w", err) } - sessionTkn, err := createSessionToken(options, oid) + box, secrets, err := accessbox.PackTokens(gatesData) 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 { return err } @@ -291,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 } @@ -305,19 +294,19 @@ func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, ownerKey *ecdsa. 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) +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 } - 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.SetContext(ctx) uid, err := uuid.New().MarshalBinary() @@ -326,19 +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) + oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey) + if err != nil { + return nil, 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 + } } - return nil, 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 d792defe..d2126f72 100644 --- a/creds/accessbox/accessbox.go +++ b/creds/accessbox/accessbox.go @@ -24,12 +24,12 @@ type GateData struct { AccessKey string BearerToken *token.BearerToken SessionToken *session.Token - OwnerKey *ecdsa.PublicKey + GateKey *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} +// 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. @@ -50,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(gatesData []*GateData, sess *session.Token) (*AccessBox, *Secrets, error) { +func PackTokens(gatesData []*GateData) (*AccessBox, *Secrets, error) { box := &AccessBox{} ephemeralKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 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) } - 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) } @@ -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) } -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 { encBearer, err := gate.BearerToken.Marshal() if err != nil { return fmt.Errorf("%w, sender = %d", err, i) } var encSession []byte - if sess != nil { + if gate.SessionToken != nil { encSession, err = gate.SessionToken.Marshal() if err != nil { 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.SessionToken = encSession - boxGate, err := encodeGate(ephemeralKey, gate.OwnerKey, tokens) + boxGate, err := encodeGate(ephemeralKey, gate.GateKey, tokens) if err != nil { return err } @@ -153,7 +153,7 @@ func decodeGate(gate *AccessBox_Gate, owner *ecdsa.PrivateKey, sender *ecdsa.Pub return nil, err } - gateData := NewGateData(bearerTkn, &owner.PublicKey) + gateData := NewGateData(&owner.PublicKey, bearerTkn) gateData.SessionToken = sessionTkn gateData.AccessKey = hex.EncodeToString(tokens.AccessKey) return gateData, nil diff --git a/creds/accessbox/bearer_token_test.go b/creds/accessbox/bearer_token_test.go index 22fff57f..d9263c72 100644 --- a/creds/accessbox/bearer_token_test.go +++ b/creds/accessbox/bearer_token_test.go @@ -6,8 +6,11 @@ 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" ) @@ -56,8 +59,8 @@ func Test_bearer_token_in_access_box(t *testing.T) { tkn.SetEACLTable(eacl.NewTable()) require.NoError(t, tkn.SignToken(sec)) - gate := NewGateData(tkn, &cred.PublicKey) - box, _, err = PackTokens([]*GateData{gate}, nil) + gate := NewGateData(&cred.PublicKey, tkn) + box, _, err = PackTokens([]*GateData{gate}) require.NoError(t, err) data, err := box.Marshal() @@ -72,6 +75,44 @@ func Test_bearer_token_in_access_box(t *testing.T) { 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) { var ( box *AccessBox @@ -92,12 +133,12 @@ func Test_accessbox_multiple_keys(t *testing.T) { cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err) - gates = append(gates, NewGateData(tkn, &cred.PublicKey)) + gates = append(gates, NewGateData(&cred.PublicKey, tkn)) keys = append(keys, cred) } } - box, _, err = PackTokens(gates, nil) + box, _, err = PackTokens(gates) require.NoError(t, err) for i, k := range keys { @@ -125,8 +166,8 @@ func Test_unknown_key(t *testing.T) { tkn.SetEACLTable(eacl.NewTable()) require.NoError(t, tkn.SignToken(sec)) - gate := NewGateData(tkn, &cred.PublicKey) - box, _, err = PackTokens([]*GateData{gate}, nil) + gate := NewGateData(&cred.PublicKey, tkn) + box, _, err = PackTokens([]*GateData{gate}) require.NoError(t, err) _, err = box.GetTokens(wrongCred)