forked from TrueCloudLab/frostfs-s3-gw
Merge pull request #90 from KirillovDenis/feature/83-use_multiple_bearer_tokens
[#83] Use multiple bearer tokens
This commit is contained in:
commit
dfbe543c61
7 changed files with 371 additions and 238 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
@ -141,34 +140,23 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
|
||||||
return err
|
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)
|
oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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",
|
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 +167,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 +195,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)
|
||||||
|
@ -302,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
|
||||||
}
|
}
|
||||||
|
@ -316,7 +294,19 @@ func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, ownerKey *ecdsa.
|
||||||
return bearerToken, bearerToken.SignToken(key)
|
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 := session.NewToken()
|
||||||
tok.SetContext(ctx)
|
tok.SetContext(ctx)
|
||||||
uid, err := uuid.New().MarshalBinary()
|
uid, err := uuid.New().MarshalBinary()
|
||||||
|
@ -325,30 +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)
|
||||||
}
|
|
||||||
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 {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := sha256.Sum256(data)
|
sessionTokens, err := buildSessionTokens(options.NeoFSKey, oid, sessionRules, options.GatesPublicKeys)
|
||||||
return hex.EncodeToString(hash[:]), nil
|
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) {
|
||||||
|
|
|
@ -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
|
||||||
|
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.
|
// 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) (*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, 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.
|
// GetTokens returns gate tokens from AccessBox.
|
||||||
func (x *AccessBox) GetBearerToken(owner *ecdsa.PrivateKey) (*token.BearerToken, error) {
|
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, 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 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
|
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(&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) {
|
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
|
|
||||||
}
|
func generateSecret() ([]byte, error) {
|
||||||
return aead, nil
|
b := make([]byte, 32)
|
||||||
|
_, err := io.ReadFull(rand.Reader, b)
|
||||||
|
return b, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
|
|
|
@ -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"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,15 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
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 +28,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 +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))
|
||||||
|
|
||||||
box, _, err = PackTokens(tkn, nil, &cred.PublicKey)
|
gate := NewGateData(&cred.PublicKey, tkn)
|
||||||
|
box, _, err = PackTokens([]*GateData{gate})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
data, err := box.Marshal()
|
data, err := box.Marshal()
|
||||||
|
@ -59,10 +69,48 @@ 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_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) {
|
||||||
|
@ -78,25 +126,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(&cred.PublicKey, tkn))
|
||||||
keys = append(keys, cred)
|
keys = append(keys, cred)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
box, _, err = PackTokens(tkn, nil, pubs...)
|
box, _, err = PackTokens(gates)
|
||||||
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 +166,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(&cred.PublicKey, tkn)
|
||||||
|
box, _, err = PackTokens([]*GateData{gate})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = box.GetBearerToken(wrongCred)
|
_, err = box.GetTokens(wrongCred)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue