Skip to content

Commit

Permalink
bearer: Set issuer explicitly on signing
Browse files Browse the repository at this point in the history
Dedicated field for the bearer token issuer was recently added to the
protocol nspcc-dev/neofs-api#266. Now SDK
provides getter and setter for it.

Previously, `Token` type accepted `neofscrypto.Signer` parameter in
`Sign` method to calculate and set signature of the bearer token.
Obviously, the method did not set nonexistent issuer field. The only way
to access the issuer was `ResolveIssuer` method resolving user ID from
the public key.

Now `Sign` method accepts parameter of `user.Signer` type to
additionally set issuer field. This is a breaking change overall, but
still needed for stable system authorization and library usage.

`ResolveIssuer` method is marked as deprecated in favor of new `Issuer`
one.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
  • Loading branch information
cthulhu-rider committed Mar 18, 2024
1 parent 6f65512 commit eecc97f
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 12 deletions.
49 changes: 45 additions & 4 deletions bearer/bearer.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ type Token struct {
targetUserSet bool
targetUser user.ID

issuerSet bool
issuer user.ID

eaclTableSet bool
eaclTable eacl.Table

Expand Down Expand Up @@ -58,6 +61,14 @@ func (b *Token) readFromV2(m acl.BearerToken, checkFieldPresence bool) error {
}
}

issuer := body.GetIssuer()
if b.issuerSet = issuer != nil; b.issuerSet {
err = b.issuer.ReadFromV2(*issuer)
if err != nil {
return fmt.Errorf("invalid issuer: %w", err)
}
}

lifetime := body.GetLifetime()
if b.lifetimeSet = lifetime != nil; b.lifetimeSet {
b.iat = lifetime.GetIat()
Expand Down Expand Up @@ -85,7 +96,7 @@ func (b *Token) ReadFromV2(m acl.BearerToken) error {
}

func (b Token) fillBody() *acl.BearerTokenBody {
if !b.eaclTableSet && !b.targetUserSet && !b.lifetimeSet {
if !b.eaclTableSet && !b.targetUserSet && !b.lifetimeSet && !b.issuerSet {
return nil
}

Expand All @@ -102,6 +113,13 @@ func (b Token) fillBody() *acl.BearerTokenBody {
body.SetOwnerID(&targetUser)
}

if b.issuerSet {
var issuer refs.OwnerID
b.issuer.WriteToV2(&issuer)

body.SetIssuer(&issuer)
}

if b.lifetimeSet {
var lifetime acl.TokenLifetime
lifetime.SetIat(b.iat)
Expand Down Expand Up @@ -244,8 +262,8 @@ func (b Token) AssertUser(id user.ID) bool {
return !b.targetUserSet || b.targetUser.Equals(id)
}

// Sign calculates and writes signature of the [Token] data using issuer's signer.
// Returns signature calculation errors.
// Sign calculates and writes signature of the [Token] data along with issuer ID
// using signer. Returns signature calculation errors.
//
// Sign MUST be called if [Token] is going to be transmitted over
// NeoFS API V2 protocol.
Expand All @@ -254,7 +272,9 @@ func (b Token) AssertUser(id user.ID) bool {
// expected to be calculated as a final stage of Token formation.
//
// See also [Token.VerifySignature], [Token.Issuer], [Token.SignedData].
func (b *Token) Sign(signer neofscrypto.Signer) error {
func (b *Token) Sign(signer user.Signer) error {
b.SetIssuer(signer.UserID())

var sig neofscrypto.Signature

err := sig.Calculate(signer, b.signedData())
Expand Down Expand Up @@ -364,10 +384,31 @@ func (b Token) SigningKeyBytes() []byte {
return nil
}

// SetIssuer sets NeoFS user ID of the [Token] issuer.
//
// See also [Token.Issuer], [Token.SignByIssuer].
func (b *Token) SetIssuer(usr user.ID) {
b.issuerSet = true
b.issuer = usr
}

// Issuer returns NeoFS user ID of the Token issuer. Zero value means unset
// issuer.
//
// See also [Token.SetIssuer].
func (b Token) Issuer() user.ID {
if b.issuerSet {
return b.issuer
}
return user.ID{}
}

// ResolveIssuer resolves issuer's [user.ID] from the key used for [Token] signing.
// Returns zero [user.ID] if Token is unsigned or key has incorrect format.
//
// See also [Token.SigningKeyBytes].
//
// Deprecated: use [Token.Issuer] instead.
func (b Token) ResolveIssuer() user.ID {
var usr user.ID
binKey := b.SigningKeyBytes()
Expand Down
58 changes: 56 additions & 2 deletions bearer/bearer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ func TestToken_Sign(t *testing.T) {

require.False(t, val.VerifySignature())

signer := test.RandomSigner(t)
signer := test.RandomSignerRFC6979(t)

val = bearertest.Token(t)

Expand Down Expand Up @@ -291,8 +291,9 @@ func TestToken_SignedData(t *testing.T) {

signer := test.RandomSignerRFC6979(t)
val = bearertest.Token(t)
val.SetIssuer(signer.UserID())

test.SignedDataComponent(t, signer, &val)
test.SignedDataComponentUser(t, signer, &val)
}

func TestToken_ReadFromV2(t *testing.T) {
Expand Down Expand Up @@ -391,3 +392,56 @@ func TestResolveIssuer(t *testing.T) {

require.Equal(t, usr, val.ResolveIssuer())
}

func TestToken_Issuer(t *testing.T) {
var token bearer.Token
var msg acl.BearerToken
filled := bearertest.Token(t)

token.WriteToV2(&msg)
require.Zero(t, msg.GetBody())

val2 := filled
require.NoError(t, val2.Unmarshal(token.Marshal()))

val2.WriteToV2(&msg)
require.Zero(t, msg.GetBody())

val2 = filled

jd, err := token.MarshalJSON()
require.NoError(t, err)

require.NoError(t, val2.UnmarshalJSON(jd))

val2.WriteToV2(&msg)
require.Zero(t, msg.GetBody())

// set value
usr := usertest.ID(t)

var usrV2 refs.OwnerID
usr.WriteToV2(&usrV2)

token.SetIssuer(usr)

token.WriteToV2(&msg)
require.Equal(t, usrV2, *msg.GetBody().GetIssuer())

val2 = filled

require.NoError(t, val2.Unmarshal(token.Marshal()))

val2.WriteToV2(&msg)
require.Equal(t, usrV2, *msg.GetBody().GetIssuer())

val2 = filled

jd, err = token.MarshalJSON()
require.NoError(t, err)

require.NoError(t, val2.UnmarshalJSON(jd))

val2.WriteToV2(&msg)
require.Equal(t, usrV2, *msg.GetBody().GetIssuer())
}
3 changes: 1 addition & 2 deletions bearer/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/nspcc-dev/neofs-sdk-go/bearer"
"github.com/nspcc-dev/neofs-sdk-go/client"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/user"
Expand All @@ -31,7 +30,7 @@ func Example() {
// Bearer token must be signed by owner of the container.
// import neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"

var signer neofscrypto.Signer
var signer user.Signer
// signer initialization, bearerToken initialization, other steps ...

_ = bearerToken.Sign(signer)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/mr-tron/base58 v1.2.0
github.com/nspcc-dev/hrw/v2 v2.0.1
github.com/nspcc-dev/neo-go v0.105.1
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240228163253-cb87bbd5e4eb
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4
github.com/nspcc-dev/tzhash v1.7.2
github.com/stretchr/testify v1.8.4
github.com/testcontainers/testcontainers-go v0.24.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ github.com/nspcc-dev/hrw/v2 v2.0.1 h1:CxYUkBeJvNfMEn2lHhrV6FjY8pZPceSxXUtMVq0BUO
github.com/nspcc-dev/hrw/v2 v2.0.1/go.mod h1:iZAs5hT2q47EGq6AZ0FjaUI6ggntOi7vrY4utfzk5VA=
github.com/nspcc-dev/neo-go v0.105.1 h1:r0b2yIwLBi+ARBKU94gHL9oTFEB/XMJ0YlS2HN9Qw34=
github.com/nspcc-dev/neo-go v0.105.1/go.mod h1:GNh0cRALV/cuj+/xg2ZHDsrFbqcInqG7jjhqsLEnlNc=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240228163253-cb87bbd5e4eb h1:vvMxf818Ea2Ql+j9QX7zOlEXDrVlbAzR0DhGvrULilQ=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240228163253-cb87bbd5e4eb/go.mod h1:7Tm1NKEoUVVIUlkVwFrPh7GG5+Lmta2m7EGr4oVpBd8=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 h1:arN0Ypn+jawZpu1BND7TGRn44InAVIqKygndsx0y2no=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4/go.mod h1:7Tm1NKEoUVVIUlkVwFrPh7GG5+Lmta2m7EGr4oVpBd8=
github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM=
github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc=
github.com/nspcc-dev/tzhash v1.7.2 h1:iRXoa9TJqH/DQO7FFcqpq9BdruF9E7/xnFGlIghl5J4=
Expand Down
2 changes: 1 addition & 1 deletion object/slicer/slicer.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ func initPayloadStream(ctx context.Context, ow ObjectWriter, header object.Objec
} else if opts.bearerToken != nil {
prm.WithBearerToken(*opts.bearerToken)
// token issuer is a container owner.
issuer := opts.bearerToken.ResolveIssuer()
issuer := opts.bearerToken.Issuer()
owner = issuer
header.SetOwnerID(&owner)
}
Expand Down

0 comments on commit eecc97f

Please sign in to comment.