[#48] creds,authmate:Replace old accessbox by new

Removed encoder, decoder wraps.
Made changes in api, authmate and creds via new accessbox.
Updated bearer_token_tests via new accessbox.

Signed-off-by: Angira Kekteeva <kira@nspcc.ru>
This commit is contained in:
Angira Kekteeva 2021-06-14 16:39:25 +03:00
parent 364257c5fd
commit fe2d507121
9 changed files with 324 additions and 376 deletions

View file

@ -15,8 +15,8 @@ import (
"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/authmate"
"github.com/nspcc-dev/neofs-s3-gw/creds/bearer"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs" "github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
"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"
) )
@ -31,7 +31,7 @@ type (
center struct { center struct {
reg *regexpSubmatcher reg *regexpSubmatcher
cli bearer.Credentials cli tokens.Credentials
} }
// Params stores node connection parameters. // Params stores node connection parameters.
@ -57,7 +57,7 @@ var _ io.ReadSeeker = prs(0)
// New creates an instance of AuthCenter. // New creates an instance of AuthCenter.
func New(conns pool.Pool, key hcs.PrivateKey) Center { func New(conns pool.Pool, key hcs.PrivateKey) Center {
return &center{ return &center{
cli: bearer.New(conns, key), cli: tokens.New(conns, key),
reg: &regexpSubmatcher{re: authorizationFieldRegexp}, reg: &regexpSubmatcher{re: authorizationFieldRegexp},
} }
} }
@ -96,7 +96,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.Get(r.Context(), address) tkn, err := c.cli.GetBearerToken(r.Context(), address)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -20,8 +20,9 @@ import (
"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/token" "github.com/nspcc-dev/neofs-api-go/pkg/token"
"github.com/nspcc-dev/neofs-node/pkg/policy" "github.com/nspcc-dev/neofs-node/pkg/policy"
"github.com/nspcc-dev/neofs-s3-gw/creds/bearer" "github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs" "github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
"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"
) )
@ -129,6 +130,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
var ( var (
err error err error
cid *cid.ID cid *cid.ID
box accessbox.AccessBox
) )
a.log.Info("check container", zap.Stringer("cid", options.ContainerID)) a.log.Info("check container", zap.Stringer("cid", options.ContainerID))
@ -148,12 +150,18 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
return fmt.Errorf("failed to build bearer token: %w", err) return fmt.Errorf("failed to build bearer token: %w", err)
} }
box.SetOwnerPublicKey(options.OwnerPrivateKey.PublicKey())
err = box.AddBearerToken(tkn, options.OwnerPrivateKey, options.GatesPublicKeys...)
if err != nil {
return fmt.Errorf("failed to add token to accessbox: %w", err)
}
a.log.Info("store bearer token into NeoFS", a.log.Info("store bearer token into NeoFS",
zap.Stringer("owner_tkn", tkn.Issuer())) zap.Stringer("owner_tkn", tkn.Issuer()))
address, err := bearer. address, err := tokens.
New(a.pool, options.OwnerPrivateKey). New(a.pool, options.OwnerPrivateKey).
Put(ctx, cid, tkn, options.GatesPublicKeys...) Put(ctx, cid, tkn.Issuer(), &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)
} }
@ -179,13 +187,13 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
// ObtainSecret receives an existing secret access key from NeoFS and // ObtainSecret receives an existing secret access key from NeoFS and
// writes to io.Writer the secret access key. // writes to io.Writer the secret access key.
func (a *Agent) ObtainSecret(ctx context.Context, w io.Writer, options *ObtainSecretOptions) error { func (a *Agent) ObtainSecret(ctx context.Context, w io.Writer, options *ObtainSecretOptions) error {
bearerCreds := bearer.New(a.pool, options.GatePrivateKey) bearerCreds := tokens.New(a.pool, options.GatePrivateKey)
address := object.NewAddress() address := object.NewAddress()
if err := address.Parse(options.SecretAddress); err != nil { if err := address.Parse(options.SecretAddress); err != nil {
return fmt.Errorf("failed to parse secret address: %w", err) return fmt.Errorf("failed to parse secret address: %w", err)
} }
tkn, err := bearerCreds.Get(ctx, address) tkn, err := bearerCreds.GetBearerToken(ctx, address)
if err != nil { if err != nil {
return fmt.Errorf("failed to get bearer token: %w", err) return fmt.Errorf("failed to get bearer token: %w", err)
} }

View file

@ -1,29 +1,184 @@
package accessbox package accessbox
import "github.com/nspcc-dev/neofs-api-go/pkg/token" import (
"bytes"
"crypto/rand"
"fmt"
type ( "github.com/nspcc-dev/neofs-api-go/pkg/session"
// Box provides marshalling/unmarshalling for the token. "github.com/nspcc-dev/neofs-api-go/pkg/token"
Box interface { "github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
Marshal() ([]byte, error) "golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/curve25519"
"google.golang.org/protobuf/proto"
)
type tokenInterface interface {
Marshal(bs ...[]byte) ([]byte, error)
Unmarshal([]byte) error Unmarshal([]byte) error
} }
// Encoder provides encoding method. // Marshal returns the wire-format of AccessBox.
Encoder interface { func (x *AccessBox) Marshal() ([]byte, error) {
Encode(Box) error return proto.Marshal(x)
} }
// Decoder provides decoding method. // Unmarshal parses the wire-format message and put data to x.
Decoder interface { func (x *AccessBox) Unmarshal(data []byte) error {
Decode(Box) error return proto.Unmarshal(data, x)
} }
// BearerTokenBox is a marshalling/unmarshalling bearer token wrapper. // AddBearerToken adds a bearer token to BearerTokens list.
BearerTokenBox interface { func (x *AccessBox) AddBearerToken(tkn *token.BearerToken, owner hcs.PrivateKey, keys ...hcs.PublicKey) error {
Box if x.OwnerPublicKey == nil {
return fmt.Errorf("owner's public key is nil")
Token() *token.BearerToken }
SetToken(*token.BearerToken) // restriction to rewrite token for the second time
if len(x.BearerTokens) > 0 {
return fmt.Errorf("bearer token is already set")
}
return x.addToken(tkn, &x.BearerTokens, owner, keys...)
}
// AddSessionToken adds a session token to SessionTokens list.
func (x *AccessBox) AddSessionToken(tkn *session.Token, owner hcs.PrivateKey, keys ...hcs.PublicKey) error {
if x.OwnerPublicKey == nil {
return fmt.Errorf("owner's public key is nil")
}
//restriction to rewrite token for the second time
if len(x.SessionTokens) > 0 {
return fmt.Errorf("bearer token is already set")
}
return x.addToken(tkn, &x.SessionTokens, owner, keys...)
}
// SetOwnerPublicKey sets a public key of an issuer.
func (x *AccessBox) SetOwnerPublicKey(key hcs.PublicKey) {
x.OwnerPublicKey = key.Bytes()
}
// GetBearerToken returns bearer token from AccessBox.
func (x *AccessBox) GetBearerToken(owner hcs.PrivateKey) (*token.BearerToken, error) {
sender, err := hcs.PublicKeyFromBytes(x.OwnerPublicKey)
if err != nil {
return nil, fmt.Errorf("failed to load owner public key from AccessBox: %w", err)
}
for _, data := range x.BearerTokens {
if !bytes.Equal(data.GatePublicKey, owner.PublicKey().Bytes()) {
continue
}
tkn := token.NewBearerToken()
if err := decodeToken(data.Token, tkn, owner, sender); err != nil {
return nil, fmt.Errorf("failed to decode bearer token: %w", err)
}
return tkn, nil
}
return nil, fmt.Errorf("no bearer token for key %s was found", owner.String())
}
// GetSessionToken returns session token from AccessBox.
func (x *AccessBox) GetSessionToken(owner hcs.PrivateKey) (*session.Token, error) {
sender, err := hcs.PublicKeyFromBytes(x.OwnerPublicKey)
if err != nil {
return nil, fmt.Errorf("failed to load owner public key from AccessBox: %w", err)
}
for _, data := range x.SessionTokens {
if !bytes.Equal(data.GatePublicKey, owner.PublicKey().Bytes()) {
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 %s was found", owner.String())
}
func (x *AccessBox) addToken(tkn tokenInterface, list *[]*AccessBox_Token, owner hcs.PrivateKey, keys ...hcs.PublicKey) error {
for i, sender := range keys {
data, err := encodeToken(tkn, owner, sender)
if err != nil {
return fmt.Errorf("%w, sender = %d", err, i)
}
*list = append(*list, newToken(data, sender.Bytes()))
}
return nil
}
func newToken(data []byte, key []byte) *AccessBox_Token {
res := new(AccessBox_Token)
res.Token = data
res.GatePublicKey = key
return res
}
func encodeToken(tkn tokenInterface, owner hcs.PrivateKey, sender hcs.PublicKey) ([]byte, error) {
data, err := tkn.Marshal()
if err != nil {
return nil, err
}
encrypted, err := encrypt(owner, sender, data)
if err != nil {
return nil, err
}
return encrypted, nil
}
func decodeToken(data []byte, tkn tokenInterface, owner hcs.PrivateKey, sender hcs.PublicKey) error {
decoded, err := decrypt(owner, sender, data)
if err != nil {
return err
}
err = tkn.Unmarshal(decoded)
if err != nil {
return err
}
return nil
}
func encrypt(owner hcs.PrivateKey, sender hcs.PublicKey, data []byte) ([]byte, error) {
key, err := curve25519.X25519(owner.Bytes(), sender.Bytes())
if err != nil {
return nil, err
}
enc, err := chacha20poly1305.NewX(key)
if err != nil {
return nil, err
}
nonce := make([]byte, enc.NonceSize(), enc.NonceSize()+len(data)+enc.Overhead())
if _, err := rand.Read(nonce); err != nil {
return nil, err
}
return enc.Seal(nonce, nonce, data, nil), nil
}
func decrypt(owner hcs.PrivateKey, sender hcs.PublicKey, data []byte) ([]byte, error) {
sb := sender.Bytes()
key, err := curve25519.X25519(owner.Bytes(), sb)
if err != nil {
return nil, err
}
dec, err := chacha20poly1305.NewX(key)
if err != nil {
return nil, err
}
if ld, ns := len(data), dec.NonceSize(); ld < ns {
return nil, fmt.Errorf("wrong data size (%d), should be greater than %d", ld, ns)
}
nonce, cypher := data[:dec.NonceSize()], data[dec.NonceSize():]
return dec.Open(nil, nonce, cypher, nil)
} }
)

View file

@ -1,43 +0,0 @@
package accessbox
import (
"github.com/nspcc-dev/neofs-api-go/pkg/token"
)
type bearerBox struct {
tkn *token.BearerToken
}
// NewBearerBox wraps given bearer token into BearerTokenBox.
func NewBearerBox(token *token.BearerToken) BearerTokenBox {
return &bearerBox{tkn: token}
}
// Marshal serializes bearer token.
func (b *bearerBox) Marshal() ([]byte, error) {
return b.tkn.Marshal(nil)
}
// Marshal initializes bearer box from its serialized representation.
func (b *bearerBox) Unmarshal(data []byte) error {
tkn := token.NewBearerToken()
err := tkn.Unmarshal(data)
if err != nil {
return err
}
b.SetToken(tkn)
return nil
}
// Token unwraps bearer token from the box.
func (b *bearerBox) Token() *token.BearerToken {
return b.tkn
}
// SetToken sets new token in the box.
func (b *bearerBox) SetToken(tkn *token.BearerToken) {
b.tkn = tkn
}

View file

@ -1,12 +1,9 @@
package accessbox package accessbox
import ( import (
"bytes"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"crypto/rand" "crypto/rand"
"encoding/binary"
"strconv"
"testing" "testing"
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl" "github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
@ -15,9 +12,34 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func Test_encrypt_decrypt(t *testing.T) { func Test_tokens_encode_decode(t *testing.T) {
tkn := token.NewBearerToken() var (
box := NewBearerBox(tkn) tkn = token.NewBearerToken()
tkn2 = token.NewBearerToken()
)
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
cred, err := hcs.Generate(rand.Reader)
require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec))
data, err := encodeToken(tkn, cred.PrivateKey(), cred.PublicKey())
require.NoError(t, err)
err = decodeToken(data, tkn2, cred.PrivateKey(), cred.PublicKey())
require.NoError(t, err)
require.Equal(t, tkn, tkn2)
}
func Test_bearer_token_in_access_box(t *testing.T) {
var (
box, box2 AccessBox
tkn = token.NewBearerToken()
)
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
@ -28,21 +50,28 @@ func Test_encrypt_decrypt(t *testing.T) {
tkn.SetEACLTable(eacl.NewTable()) tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec)) require.NoError(t, tkn.SignToken(sec))
box.SetOwnerPublicKey(cred.PublicKey())
err = box.AddBearerToken(tkn, cred.PrivateKey(), cred.PublicKey())
require.NoError(t, err)
data, err := box.Marshal() data, err := box.Marshal()
require.NoError(t, err) require.NoError(t, err)
encrypted, err := encrypt(cred.PrivateKey(), cred.PublicKey(), data) err = box2.Unmarshal(data)
require.NoError(t, err) require.NoError(t, err)
decrypted, err := decrypt(cred.PrivateKey(), cred.PublicKey(), encrypted) tkn2, err := box2.GetBearerToken(cred.PrivateKey())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, data, decrypted) require.Equal(t, tkn, tkn2)
} }
func Test_encrypt_decrypt_step_by_step(t *testing.T) { func Test_accessbox_multiple_keys(t *testing.T) {
tkn := token.NewBearerToken() var (
box := NewBearerBox(tkn) box AccessBox
tkn = token.NewBearerToken()
)
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
@ -53,75 +82,6 @@ func Test_encrypt_decrypt_step_by_step(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 := box.Marshal()
require.NoError(t, err)
buf := new(bytes.Buffer)
_, err = cred.PublicKey().WriteTo(buf)
require.NoError(t, err)
encrypted, err := encrypt(cred.PrivateKey(), cred.PublicKey(), data)
require.NoError(t, err)
length := len(encrypted)
temp := make([]byte, length+binary.MaxVarintLen64)
size := binary.PutVarint(temp, int64(length))
copy(temp[size:], encrypted)
buf.Write(temp[:length+size])
sender, err := hcs.NewPublicKeyFromReader(buf)
require.NoError(t, err)
require.Equal(t, cred.PublicKey(), sender)
ln, err := binary.ReadVarint(buf)
require.NoError(t, err)
require.Equal(t, int64(length), ln)
enc := make([]byte, ln)
n, err := buf.Read(enc)
require.NoError(t, err)
require.Equal(t, length, n)
require.Equal(t, encrypted, enc)
decrypted, err := decrypt(cred.PrivateKey(), sender, enc)
require.NoError(t, err)
require.Equal(t, data, decrypted)
}
func TestSingleKey_AccessBox(t *testing.T) {
tkn := token.NewBearerToken()
expect := NewBearerBox(tkn)
actual := NewBearerBox(nil)
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
cred, err := hcs.Generate(rand.Reader)
require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec))
data, err := Encode(expect, cred.PrivateKey(), cred.PublicKey())
require.NoError(t, err)
require.NoError(t, Decode(data, actual, cred.PrivateKey()))
require.Equal(t, expect, actual)
}
func TestBearerToken_AccessBox(t *testing.T) {
tkn := token.NewBearerToken()
box := NewBearerBox(tkn)
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
cred, err := hcs.Generate(rand.Reader)
require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec))
count := 10 count := 10
pubs := make([]hcs.PublicKey, 0, count) pubs := make([]hcs.PublicKey, 0, count)
keys := make([]hcs.PrivateKey, 0, count) keys := make([]hcs.PrivateKey, 0, count)
@ -135,27 +95,41 @@ func TestBearerToken_AccessBox(t *testing.T) {
} }
} }
buf := new(bytes.Buffer) box.SetOwnerPublicKey(cred.PublicKey())
require.NoError(t, NewEncoder(buf, cred.PrivateKey(), pubs...).Encode(box))
data := buf.Bytes() err = box.AddBearerToken(tkn, cred.PrivateKey(), pubs...)
for i := range keys {
key := keys[i]
t.Run("try with key "+strconv.Itoa(i), func(t *testing.T) {
r := bytes.NewReader(data)
nbx := NewBearerBox(nil)
require.NoError(t, NewDecoder(r, key).Decode(nbx))
require.Equal(t, tkn, nbx.Token())
})
}
t.Run("should fail for unknown key", func(t *testing.T) {
cred, err = hcs.Generate(rand.Reader)
require.NoError(t, err) require.NoError(t, err)
r := bytes.NewReader(data) for i, k := range keys {
nbx := NewBearerBox(nil) tkn2, err := box.GetBearerToken(k)
require.EqualError(t, NewDecoder(r, cred.PrivateKey()).Decode(nbx), "chacha20poly1305: message authentication failed") require.NoError(t, err, "key #%d: %s failed", i, k)
}) require.Equal(t, tkn2, tkn)
}
}
func Test_unknown_key(t *testing.T) {
var (
box AccessBox
tkn = token.NewBearerToken()
)
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
cred, err := hcs.Generate(rand.Reader)
require.NoError(t, err)
wrongCred, err := hcs.Generate(rand.Reader)
require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec))
box.SetOwnerPublicKey(cred.PublicKey())
err = box.AddBearerToken(tkn, cred.PrivateKey(), cred.PublicKey())
require.NoError(t, err)
_, err = box.GetBearerToken(wrongCred.PrivateKey())
require.Error(t, err)
} }

View file

@ -1,88 +0,0 @@
package accessbox
import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"io"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/curve25519"
)
type decoder struct {
*bufio.Reader
key hcs.PrivateKey
}
// NewDecoder returns new private key decoder.
func NewDecoder(r io.Reader, key hcs.PrivateKey) Decoder {
return &decoder{Reader: bufio.NewReader(r), key: key}
}
func decrypt(owner hcs.PrivateKey, sender hcs.PublicKey, data []byte) ([]byte, error) {
sb := sender.Bytes()
key, err := curve25519.X25519(owner.Bytes(), sb)
if err != nil {
return nil, err
}
dec, err := chacha20poly1305.NewX(key)
if err != nil {
return nil, err
}
if ld, ns := len(data), dec.NonceSize(); ld < ns {
return nil, fmt.Errorf("wrong data size (%d), should be greater than %d", ld, ns)
}
nonce, cypher := data[:dec.NonceSize()], data[dec.NonceSize():]
return dec.Open(nil, nonce, cypher, nil)
}
func (d *decoder) Decode(box Box) error {
sender, err := hcs.NewPublicKeyFromReader(d)
if err != nil {
return err
}
var lastErr error
for {
size, err := binary.ReadVarint(d)
if err == io.EOF {
break
} else if err != nil {
return err
}
data := make([]byte, size)
if ln, err := d.Read(data); err != nil {
lastErr = err
continue
} else if ln != int(size) {
lastErr = fmt.Errorf("expect %d bytes, but read only %d bytes", size, ln)
continue
} else if decoded, err := decrypt(d.key, sender, data); err != nil {
lastErr = err
continue
} else if err = box.Unmarshal(decoded); err != nil {
lastErr = err
continue
}
return nil
}
return lastErr
}
// Decode unwraps serialized bearer token from data into box using owner key.
func Decode(data []byte, box Box, owner hcs.PrivateKey) error {
return NewDecoder(bytes.NewBuffer(data), owner).Decode(box)
}

View file

@ -1,85 +0,0 @@
package accessbox
import (
"bytes"
"crypto/rand"
"encoding/binary"
"fmt"
"io"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/curve25519"
)
type encoder struct {
io.Writer
owner hcs.PrivateKey
keys []hcs.PublicKey
}
// NewEncoder creates encoder.
func NewEncoder(w io.Writer, owner hcs.PrivateKey, keys ...hcs.PublicKey) Encoder {
return &encoder{
Writer: w,
owner: owner,
keys: keys,
}
}
func encrypt(owner hcs.PrivateKey, sender hcs.PublicKey, data []byte) ([]byte, error) {
key, err := curve25519.X25519(owner.Bytes(), sender.Bytes())
if err != nil {
return nil, err
}
enc, err := chacha20poly1305.NewX(key)
if err != nil {
return nil, err
}
nonce := make([]byte, enc.NonceSize(), enc.NonceSize()+len(data)+enc.Overhead())
if _, err := rand.Read(nonce); err != nil {
return nil, err
}
return enc.Seal(nonce, nonce, data, nil), nil
}
// Encode and encrypt box through owner private key and public keys.
func (e *encoder) Encode(box Box) error {
data, err := box.Marshal()
if err != nil {
return err
}
// write owner public key
if _, err = e.owner.PublicKey().WriteTo(e); err != nil {
return err
}
for i, sender := range e.keys {
encrypted, err := encrypt(e.owner, sender, data)
if err != nil {
return fmt.Errorf("%w, sender = %d", err, i)
}
ln := len(encrypted)
temp := make([]byte, ln+binary.MaxVarintLen64)
size := binary.PutVarint(temp, int64(ln))
copy(temp[size:], encrypted)
if _, err := e.Write(temp[:size+ln]); err != nil {
return fmt.Errorf("%w, sender = %d", err, i)
}
}
return nil
}
// Encode and encrypt box through owner private key and public keys.
func Encode(box Box, owner hcs.PrivateKey, keys ...hcs.PublicKey) ([]byte, error) {
buf := new(bytes.Buffer)
err := NewEncoder(buf, owner, keys...).Encode(box)
return buf.Bytes(), err
}

View file

@ -26,7 +26,8 @@ func (p *public) WriteTo(w io.Writer) (int64, error) {
return int64(pl), err return int64(pl), err
} }
func publicKeyFromBytes(v []byte) (PublicKey, error) { // PublicKeyFromBytes reads a public key from given bytes.
func PublicKeyFromBytes(v []byte) (PublicKey, error) {
pub := public(v) pub := public(v)
return &pub, nil return &pub, nil
} }
@ -37,7 +38,7 @@ func publicKeyFromString(val string) (PublicKey, error) {
return nil, err return nil, err
} }
return publicKeyFromBytes(v) return PublicKeyFromBytes(v)
} }
// NewPublicKeyFromReader reads new public key from given reader. // NewPublicKeyFromReader reads new public key from given reader.
@ -47,7 +48,7 @@ func NewPublicKeyFromReader(r io.Reader) (PublicKey, error) {
return nil, err return nil, err
} }
return publicKeyFromBytes(data) return PublicKeyFromBytes(data)
} }
// LoadPublicKey loads public key from given file or (serialized) string. // LoadPublicKey loads public key from given file or (serialized) string.
@ -61,5 +62,5 @@ func LoadPublicKey(val string) (PublicKey, error) {
return nil, err return nil, err
} }
return publicKeyFromBytes(data) return PublicKeyFromBytes(data)
} }

View file

@ -1,4 +1,4 @@
package bearer package tokens
import ( import (
"bytes" "bytes"
@ -11,6 +11,8 @@ import (
"github.com/nspcc-dev/neofs-api-go/pkg/client" "github.com/nspcc-dev/neofs-api-go/pkg/client"
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/session"
"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/creds/accessbox" "github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs" "github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
@ -20,8 +22,9 @@ import (
type ( type (
// Credentials is a bearer token get/put interface. // Credentials is a bearer token get/put interface.
Credentials interface { Credentials interface {
Get(context.Context, *object.Address) (*token.BearerToken, error) GetBearerToken(context.Context, *object.Address) (*token.BearerToken, error)
Put(context.Context, *cid.ID, *token.BearerToken, ...hcs.PublicKey) (*object.Address, error) GetSessionToken(context.Context, *object.Address) (*session.Token, error)
Put(context.Context, *cid.ID, *owner.ID, *accessbox.AccessBox, ...hcs.PublicKey) (*object.Address, error)
} }
cred struct { cred struct {
@ -59,11 +62,39 @@ func (c *cred) releaseBuffer(buf *bytes.Buffer) {
bufferPool.Put(buf) bufferPool.Put(buf)
} }
func (c *cred) Get(ctx context.Context, address *object.Address) (*token.BearerToken, error) { func (c *cred) GetBearerToken(ctx context.Context, address *object.Address) (*token.BearerToken, error) {
buf := c.acquireBuffer() box, err := c.getAccessBox(ctx, address)
defer c.releaseBuffer(buf) if err != nil {
return nil, err
}
box := accessbox.NewBearerBox(nil) tkn, err := box.GetBearerToken(c.key)
if err != nil {
return nil, err
}
return tkn, nil
}
func (c *cred) GetSessionToken(ctx context.Context, address *object.Address) (*session.Token, error) {
box, err := c.getAccessBox(ctx, address)
if err != nil {
return nil, err
}
tkn, err := box.GetSessionToken(c.key)
if err != nil {
return nil, err
}
return tkn, nil
}
func (c *cred) getAccessBox(ctx context.Context, address *object.Address) (*accessbox.AccessBox, error) {
var (
box accessbox.AccessBox
buf = c.acquireBuffer()
)
defer c.releaseBuffer(buf)
conn, tok, err := c.pool.Connection() conn, tok, err := c.pool.Connection()
if err != nil { if err != nil {
@ -80,30 +111,25 @@ func (c *cred) Get(ctx context.Context, address *object.Address) (*token.BearerT
return nil, err return nil, err
} }
err = accessbox.NewDecoder(buf, c.key).Decode(box) if err = box.Unmarshal(buf.Bytes()); err != nil {
if err != nil {
return nil, err return nil, err
} }
return &box, nil
return box.Token(), nil
} }
func (c *cred) Put(ctx context.Context, cid *cid.ID, tkn *token.BearerToken, keys ...hcs.PublicKey) (*object.Address, error) { func (c *cred) Put(ctx context.Context, cid *cid.ID, issuer *owner.ID, box *accessbox.AccessBox, keys ...hcs.PublicKey) (*object.Address, error) {
var ( var (
err error err error
buf = c.acquireBuffer()
box = accessbox.NewBearerBox(tkn)
created = strconv.FormatInt(time.Now().Unix(), 10) created = strconv.FormatInt(time.Now().Unix(), 10)
) )
defer c.releaseBuffer(buf)
if len(keys) == 0 { if len(keys) == 0 {
return nil, ErrEmptyPublicKeys return nil, ErrEmptyPublicKeys
} else if tkn == nil { } else if box == nil {
return nil, ErrEmptyBearerToken return nil, ErrEmptyBearerToken
} else if err = accessbox.NewEncoder(buf, c.key, keys...).Encode(box); err != nil { }
data, err := box.Marshal()
if err != nil {
return nil, err return nil, err
} }
@ -121,10 +147,10 @@ func (c *cred) Put(ctx context.Context, cid *cid.ID, tkn *token.BearerToken, key
raw := object.NewRaw() raw := object.NewRaw()
raw.SetContainerID(cid) raw.SetContainerID(cid)
raw.SetOwnerID(tkn.Issuer()) raw.SetOwnerID(issuer)
raw.SetAttributes(filename, timestamp) raw.SetAttributes(filename, timestamp)
ops := new(client.PutObjectParams).WithObject(raw.Object()).WithPayloadReader(buf) ops := new(client.PutObjectParams).WithObject(raw.Object()).WithPayloadReader(bytes.NewBuffer(data))
oid, err := conn.PutObject( oid, err := conn.PutObject(
ctx, ctx,
ops, ops,