forked from TrueCloudLab/frostfs-sdk-go
[#259] bearer: Align with the protocol
Sync lifetime names with `session` package. Add `AssertContainer` and `AssertUser` methods which cover specific cases describe in protocol. Increase test coverage. Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
82d762f536
commit
c65be6d469
3 changed files with 648 additions and 282 deletions
520
bearer/bearer.go
520
bearer/bearer.go
|
@ -2,40 +2,121 @@ package bearer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/acl"
|
"github.com/nspcc-dev/neofs-api-go/v2/acl"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
|
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
|
||||||
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
errNilBearerTokenBody = errors.New("bearer token body is not set")
|
|
||||||
errNilBearerTokenEACL = errors.New("bearer token ContainerEACL table is not set")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Token represents bearer token for object service operations.
|
// Token represents bearer token for object service operations.
|
||||||
//
|
//
|
||||||
// Token is mutually compatible with github.com/nspcc-dev/neofs-api-go/v2/acl.BearerToken
|
// Token is mutually compatible with github.com/nspcc-dev/neofs-api-go/v2/acl.BearerToken
|
||||||
// message. See ReadFromV2 / WriteToV2 methods.
|
// message. See ReadFromV2 / WriteToV2 methods.
|
||||||
//
|
//
|
||||||
// Instances can be created using built-in var declaration.
|
// Instances can be created using built-in var declaration.
|
||||||
//
|
type Token struct {
|
||||||
// Note that direct typecast is not safe and may result in loss of compatibility:
|
targetUserSet bool
|
||||||
// _ = Token(acl.BearerToken{}) // not recommended
|
targetUser user.ID
|
||||||
type Token acl.BearerToken
|
|
||||||
|
eaclTableSet bool
|
||||||
|
eaclTable eacl.Table
|
||||||
|
|
||||||
|
lifetimeSet bool
|
||||||
|
iat, nbf, exp uint64
|
||||||
|
|
||||||
|
sigSet bool
|
||||||
|
sig refs.Signature
|
||||||
|
}
|
||||||
|
|
||||||
|
// reads Token from the acl.BearerToken message. If checkFieldPresence is set,
|
||||||
|
// returns an error on absence of any protocol-required field.
|
||||||
|
func (b *Token) readFromV2(m acl.BearerToken, checkFieldPresence bool) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
body := m.GetBody()
|
||||||
|
if checkFieldPresence && body == nil {
|
||||||
|
return errors.New("missing token body")
|
||||||
|
}
|
||||||
|
|
||||||
|
eaclTable := body.GetEACL()
|
||||||
|
if b.eaclTableSet = eaclTable != nil; b.eaclTableSet {
|
||||||
|
b.eaclTable = *eacl.NewTableFromV2(eaclTable)
|
||||||
|
} else if checkFieldPresence {
|
||||||
|
return errors.New("missing eACL table")
|
||||||
|
}
|
||||||
|
|
||||||
|
targetUser := body.GetOwnerID()
|
||||||
|
if b.targetUserSet = targetUser != nil; b.targetUserSet {
|
||||||
|
err = b.targetUser.ReadFromV2(*targetUser)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid target user: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifetime := body.GetLifetime()
|
||||||
|
if b.lifetimeSet = lifetime != nil; b.lifetimeSet {
|
||||||
|
b.iat = lifetime.GetIat()
|
||||||
|
b.nbf = lifetime.GetNbf()
|
||||||
|
b.exp = lifetime.GetExp()
|
||||||
|
} else if checkFieldPresence {
|
||||||
|
return errors.New("missing token lifetime")
|
||||||
|
}
|
||||||
|
|
||||||
|
sig := m.GetSignature()
|
||||||
|
if b.sigSet = sig != nil; sig != nil {
|
||||||
|
b.sig = *sig
|
||||||
|
} else if checkFieldPresence {
|
||||||
|
return errors.New("missing body signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ReadFromV2 reads Token from the acl.BearerToken message.
|
// ReadFromV2 reads Token from the acl.BearerToken message.
|
||||||
//
|
//
|
||||||
// See also WriteToV2.
|
// See also WriteToV2.
|
||||||
func (b *Token) ReadFromV2(m acl.BearerToken) {
|
func (b *Token) ReadFromV2(m acl.BearerToken) error {
|
||||||
*b = Token(m)
|
return b.readFromV2(m, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Token) fillBody() *acl.BearerTokenBody {
|
||||||
|
if !b.eaclTableSet && !b.targetUserSet && !b.lifetimeSet {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var body acl.BearerTokenBody
|
||||||
|
|
||||||
|
if b.eaclTableSet {
|
||||||
|
body.SetEACL(b.eaclTable.ToV2())
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.targetUserSet {
|
||||||
|
var targetUser refs.OwnerID
|
||||||
|
b.targetUser.WriteToV2(&targetUser)
|
||||||
|
|
||||||
|
body.SetOwnerID(&targetUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.lifetimeSet {
|
||||||
|
var lifetime acl.TokenLifetime
|
||||||
|
lifetime.SetIat(b.iat)
|
||||||
|
lifetime.SetNbf(b.nbf)
|
||||||
|
lifetime.SetExp(b.exp)
|
||||||
|
|
||||||
|
body.SetLifetime(&lifetime)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &body
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Token) signedData() []byte {
|
||||||
|
return b.fillBody().StableMarshal(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteToV2 writes Token to the acl.BearerToken message.
|
// WriteToV2 writes Token to the acl.BearerToken message.
|
||||||
|
@ -43,294 +124,247 @@ func (b *Token) ReadFromV2(m acl.BearerToken) {
|
||||||
//
|
//
|
||||||
// See also ReadFromV2.
|
// See also ReadFromV2.
|
||||||
func (b Token) WriteToV2(m *acl.BearerToken) {
|
func (b Token) WriteToV2(m *acl.BearerToken) {
|
||||||
*m = (acl.BearerToken)(b)
|
m.SetBody(b.fillBody())
|
||||||
|
|
||||||
|
var sig *refs.Signature
|
||||||
|
|
||||||
|
if b.sigSet {
|
||||||
|
sig = &b.sig
|
||||||
|
}
|
||||||
|
|
||||||
|
m.SetSignature(sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetExpiration sets "exp" (expiration time) claim which identifies the
|
// SetExp sets "exp" (expiration time) claim which identifies the
|
||||||
// expiration time (in NeoFS epochs) on or after which the Token MUST NOT be
|
// expiration time (in NeoFS epochs) on or after which the Token MUST NOT be
|
||||||
// accepted for processing. The processing of the "exp" claim requires that the
|
// accepted for processing. The processing of the "exp" claim requires that the
|
||||||
// current epoch MUST be before the expiration epoch listed in the "exp" claim.
|
// current epoch MUST be before the expiration epoch listed in the "exp" claim.
|
||||||
//
|
//
|
||||||
// Naming is inspired by https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4.
|
// Naming is inspired by https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4.
|
||||||
//
|
//
|
||||||
// See also Expiration.
|
// See also InvalidAt.
|
||||||
func (b *Token) SetExpiration(exp uint64) {
|
func (b *Token) SetExp(exp uint64) {
|
||||||
v2token := (*acl.BearerToken)(b)
|
b.exp = exp
|
||||||
|
b.lifetimeSet = true
|
||||||
body := v2token.GetBody()
|
|
||||||
if body == nil {
|
|
||||||
body = new(acl.BearerTokenBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
lt := new(acl.TokenLifetime)
|
|
||||||
lt.SetExp(exp)
|
|
||||||
lt.SetNbf(body.GetLifetime().GetNbf())
|
|
||||||
lt.SetIat(body.GetLifetime().GetIat())
|
|
||||||
|
|
||||||
body.SetLifetime(lt)
|
|
||||||
v2token.SetBody(body)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expiration returns "exp" claim.
|
// SetNbf sets "nbf" (not before) claim which identifies the time (in
|
||||||
//
|
|
||||||
// Empty Token has zero "exp".
|
|
||||||
//
|
|
||||||
// See also SetExpiration.
|
|
||||||
func (b Token) Expiration() uint64 {
|
|
||||||
v2token := (acl.BearerToken)(b)
|
|
||||||
return v2token.GetBody().GetLifetime().GetExp()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetNotBefore sets "nbf" (not before) claim which identifies the time (in
|
|
||||||
// NeoFS epochs) before which the Token MUST NOT be accepted for processing. The
|
// NeoFS epochs) before which the Token MUST NOT be accepted for processing. The
|
||||||
// processing of the "nbf" claim requires that the current epoch MUST be
|
// processing of the "nbf" claim requires that the current epoch MUST be
|
||||||
// after or equal to the not-before epoch listed in the "nbf" claim.
|
// after or equal to the not-before epoch listed in the "nbf" claim.
|
||||||
//
|
//
|
||||||
// Naming is inspired by https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5.
|
// Naming is inspired by https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5.
|
||||||
//
|
//
|
||||||
// See also NotBefore.
|
// See also InvalidAt.
|
||||||
func (b *Token) SetNotBefore(nbf uint64) {
|
func (b *Token) SetNbf(nbf uint64) {
|
||||||
v2token := (*acl.BearerToken)(b)
|
b.nbf = nbf
|
||||||
|
b.lifetimeSet = true
|
||||||
body := v2token.GetBody()
|
|
||||||
if body == nil {
|
|
||||||
body = new(acl.BearerTokenBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
lt := new(acl.TokenLifetime)
|
|
||||||
lt.SetExp(body.GetLifetime().GetExp())
|
|
||||||
lt.SetNbf(nbf)
|
|
||||||
lt.SetIat(body.GetLifetime().GetIat())
|
|
||||||
|
|
||||||
body.SetLifetime(lt)
|
|
||||||
v2token.SetBody(body)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotBefore returns "nbf" claim.
|
// SetIat sets "iat" (issued at) claim which identifies the time (in NeoFS
|
||||||
//
|
|
||||||
// Empty Token has zero "nbf".
|
|
||||||
//
|
|
||||||
// See also SetNotBefore.
|
|
||||||
func (b Token) NotBefore() uint64 {
|
|
||||||
v2token := (acl.BearerToken)(b)
|
|
||||||
return v2token.GetBody().GetLifetime().GetNbf()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetIssuedAt sets "iat" (issued at) claim which identifies the time (in NeoFS
|
|
||||||
// epochs) at which the Token was issued. This claim can be used to determine
|
// epochs) at which the Token was issued. This claim can be used to determine
|
||||||
// the age of the Token.
|
// the age of the Token.
|
||||||
//
|
//
|
||||||
// Naming is inspired by https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6.
|
// Naming is inspired by https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6.
|
||||||
//
|
//
|
||||||
// See also IssuedAt.
|
// See also InvalidAt.
|
||||||
func (b *Token) SetIssuedAt(iat uint64) {
|
func (b *Token) SetIat(iat uint64) {
|
||||||
v2token := (*acl.BearerToken)(b)
|
b.iat = iat
|
||||||
|
b.lifetimeSet = true
|
||||||
body := v2token.GetBody()
|
|
||||||
if body == nil {
|
|
||||||
body = new(acl.BearerTokenBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
lt := new(acl.TokenLifetime)
|
|
||||||
lt.SetExp(body.GetLifetime().GetExp())
|
|
||||||
lt.SetNbf(body.GetLifetime().GetNbf())
|
|
||||||
lt.SetIat(iat)
|
|
||||||
|
|
||||||
body.SetLifetime(lt)
|
|
||||||
v2token.SetBody(body)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IssuedAt returns "iat" claim.
|
// InvalidAt asserts "exp", "nbf" and "iat" claims for the given epoch.
|
||||||
//
|
//
|
||||||
// Empty Token has zero "iat".
|
// Zero Container is invalid in any epoch.
|
||||||
//
|
//
|
||||||
// See also SetIssuedAt.
|
// See also SetExp, SetNbf, SetIat.
|
||||||
func (b Token) IssuedAt() uint64 {
|
func (b Token) InvalidAt(epoch uint64) bool {
|
||||||
v2token := (acl.BearerToken)(b)
|
return !b.lifetimeSet || b.nbf > epoch || b.iat > epoch || b.exp <= epoch
|
||||||
return v2token.GetBody().GetLifetime().GetIat()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEACLTable sets extended ACL table that should be used during object
|
// SetEACLTable sets eacl.Table that replaces the one from the issuer's
|
||||||
// service request processing with bearer token.
|
// container. If table has specified container, bearer token can be used only
|
||||||
|
// for operations within this specific container. Otherwise, Token can be used
|
||||||
|
// within any issuer's container.
|
||||||
//
|
//
|
||||||
// See also EACLTable.
|
// SetEACLTable MUST be called if Token is going to be transmitted over
|
||||||
|
// NeoFS API V2 protocol.
|
||||||
|
//
|
||||||
|
// See also EACLTable, AssertContainer.
|
||||||
func (b *Token) SetEACLTable(table eacl.Table) {
|
func (b *Token) SetEACLTable(table eacl.Table) {
|
||||||
v2 := (*acl.BearerToken)(b)
|
b.eaclTable = table
|
||||||
|
b.eaclTableSet = true
|
||||||
body := v2.GetBody()
|
|
||||||
if body == nil {
|
|
||||||
body = new(acl.BearerTokenBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
body.SetEACL(table.ToV2())
|
|
||||||
v2.SetBody(body)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EACLTable returns extended ACL table that should be used during object
|
// EACLTable returns extended ACL table set by SetEACLTable.
|
||||||
// service request processing with bearer token.
|
//
|
||||||
|
// Zero Token has zero eacl.Table.
|
||||||
|
func (b Token) EACLTable() eacl.Table {
|
||||||
|
if b.eaclTableSet {
|
||||||
|
return b.eaclTable
|
||||||
|
}
|
||||||
|
|
||||||
|
return eacl.Table{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssertContainer checks if the token is valid within the given container.
|
||||||
|
//
|
||||||
|
// Note: cnr is assumed to refer to the issuer's container, otherwise the check
|
||||||
|
// is meaningless.
|
||||||
|
//
|
||||||
|
// Zero Token is valid in any container.
|
||||||
//
|
//
|
||||||
// See also SetEACLTable.
|
// See also SetEACLTable.
|
||||||
func (b Token) EACLTable() eacl.Table {
|
func (b Token) AssertContainer(cnr cid.ID) bool {
|
||||||
v2 := (acl.BearerToken)(b)
|
if !b.eaclTableSet {
|
||||||
return *eacl.NewTableFromV2(v2.GetBody().GetEACL())
|
return true
|
||||||
}
|
|
||||||
|
|
||||||
// SetOwnerID sets user.ID value of the user who can attach bearer token to
|
|
||||||
// its requests.
|
|
||||||
//
|
|
||||||
// See also OwnerID.
|
|
||||||
func (b *Token) SetOwnerID(id user.ID) {
|
|
||||||
v2 := (*acl.BearerToken)(b)
|
|
||||||
|
|
||||||
body := v2.GetBody()
|
|
||||||
if body == nil {
|
|
||||||
body = new(acl.BearerTokenBody)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var idV2 refs.OwnerID
|
cnrTable, set := b.eaclTable.CID()
|
||||||
id.WriteToV2(&idV2)
|
return !set || cnrTable.Equals(cnr)
|
||||||
|
|
||||||
body.SetOwnerID(&idV2)
|
|
||||||
v2.SetBody(body)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OwnerID returns user.ID value of the user who can attach bearer token to
|
// ForUser specifies ID of the user who can use the Token for the operations
|
||||||
// its requests.
|
// within issuer's container(s).
|
||||||
//
|
//
|
||||||
// See also SetOwnerID.
|
// Optional: by default, any user has access to Token usage.
|
||||||
func (b Token) OwnerID() user.ID {
|
//
|
||||||
v2 := (acl.BearerToken)(b)
|
// See also AssertUser.
|
||||||
|
func (b *Token) ForUser(id user.ID) {
|
||||||
var id user.ID
|
b.targetUser = id
|
||||||
|
b.targetUserSet = true
|
||||||
idV2 := v2.GetBody().GetOwnerID()
|
|
||||||
if idV2 != nil {
|
|
||||||
_ = id.ReadFromV2(*idV2)
|
|
||||||
}
|
|
||||||
|
|
||||||
return id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign signs bearer token. This method should be invoked with the private
|
// AssertUser checks if the Token is issued to the given user.
|
||||||
// key of container owner to allow overriding extended ACL table of the container
|
|
||||||
// included in this token.
|
|
||||||
//
|
//
|
||||||
// See also Signature.
|
// Zero Token is available to any user.
|
||||||
|
//
|
||||||
|
// See also ForUser.
|
||||||
|
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 secret.
|
||||||
|
// Returns signature calculation errors.
|
||||||
|
//
|
||||||
|
// Sign MUST be called if Token is going to be transmitted over
|
||||||
|
// NeoFS API V2 protocol.
|
||||||
|
//
|
||||||
|
// Note that any Token mutation is likely to break the signature, so it is
|
||||||
|
// expected to be calculated as a final stage of Token formation.
|
||||||
|
//
|
||||||
|
// See also VerifySignature, Issuer.
|
||||||
func (b *Token) Sign(key ecdsa.PrivateKey) error {
|
func (b *Token) Sign(key ecdsa.PrivateKey) error {
|
||||||
err := sanityCheck(b)
|
var sig neofscrypto.Signature
|
||||||
|
|
||||||
|
err := sig.Calculate(neofsecdsa.Signer(key), b.signedData())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m := (*acl.BearerToken)(b)
|
sig.WriteToV2(&b.sig)
|
||||||
|
b.sigSet = true
|
||||||
var sig neofscrypto.Signature
|
|
||||||
|
|
||||||
err = sig.Calculate(neofsecdsa.Signer(key), m.GetBody().StableMarshal(nil))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("calculate signature: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var sigV2 refs.Signature
|
|
||||||
sig.WriteToV2(&sigV2)
|
|
||||||
|
|
||||||
m.SetSignature(&sigV2)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifySignature returns nil if bearer token contains correct signature.
|
// VerifySignature checks if Token signature is presented and valid.
|
||||||
func (b Token) VerifySignature() error {
|
|
||||||
if b.isEmpty() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
m := (acl.BearerToken)(b)
|
|
||||||
|
|
||||||
sigV2 := m.GetSignature()
|
|
||||||
if sigV2 == nil {
|
|
||||||
return errors.New("missing signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
var sig neofscrypto.Signature
|
|
||||||
sig.ReadFromV2(*sigV2)
|
|
||||||
|
|
||||||
if !sig.Verify(m.GetBody().StableMarshal(nil)) {
|
|
||||||
return errors.New("wrong signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issuer returns user.ID associated with the key that signed bearer token.
|
|
||||||
// To pass node validation it should be owner of requested container.
|
|
||||||
//
|
//
|
||||||
// If token is not signed, Issuer returns empty owner ID and false `ok` flag.
|
// Zero Token fails the check.
|
||||||
//
|
//
|
||||||
// See also Sign.
|
// See also Sign.
|
||||||
func (b Token) Issuer() (id user.ID, ok bool) {
|
func (b Token) VerifySignature() bool {
|
||||||
v2 := (acl.BearerToken)(b)
|
if !b.sigSet {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
pub, _ := keys.NewPublicKeyFromBytes(v2.GetSignature().GetKey(), elliptic.P256())
|
var sig neofscrypto.Signature
|
||||||
|
sig.ReadFromV2(b.sig)
|
||||||
|
|
||||||
ok = pub != nil
|
// TODO: (#233) check owner<->key relation
|
||||||
if ok {
|
return sig.Verify(b.signedData())
|
||||||
user.IDFromKey(&id, (ecdsa.PublicKey)(*pub))
|
}
|
||||||
|
|
||||||
|
// Marshal encodes Token into a binary format of the NeoFS API protocol
|
||||||
|
// (Protocol Buffers V3 with direct field order).
|
||||||
|
//
|
||||||
|
// See also Unmarshal.
|
||||||
|
func (b Token) Marshal() []byte {
|
||||||
|
var m acl.BearerToken
|
||||||
|
b.WriteToV2(&m)
|
||||||
|
|
||||||
|
return m.StableMarshal(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal decodes NeoFS API protocol binary data into the Token
|
||||||
|
// (Protocol Buffers V3 with direct field order). Returns an error describing
|
||||||
|
// a format violation.
|
||||||
|
//
|
||||||
|
// See also Marshal.
|
||||||
|
func (b *Token) Unmarshal(data []byte) error {
|
||||||
|
var m acl.BearerToken
|
||||||
|
|
||||||
|
err := m.Unmarshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.readFromV2(m, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes Token into a JSON format of the NeoFS API protocol
|
||||||
|
// (Protocol Buffers V3 JSON).
|
||||||
|
//
|
||||||
|
// See also UnmarshalJSON.
|
||||||
|
func (b Token) MarshalJSON() ([]byte, error) {
|
||||||
|
var m acl.BearerToken
|
||||||
|
b.WriteToV2(&m)
|
||||||
|
|
||||||
|
return m.MarshalJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes NeoFS API protocol JSON data into the Token
|
||||||
|
// (Protocol Buffers V3 JSON). Returns an error describing a format violation.
|
||||||
|
//
|
||||||
|
// See also MarshalJSON.
|
||||||
|
func (b *Token) UnmarshalJSON(data []byte) error {
|
||||||
|
var m acl.BearerToken
|
||||||
|
|
||||||
|
err := m.UnmarshalJSON(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.readFromV2(m, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SigningKeyBytes returns issuer's public key in a binary format of
|
||||||
|
// NeoFS API protocol.
|
||||||
|
//
|
||||||
|
// Unsigned Token has empty key.
|
||||||
|
//
|
||||||
|
// See also ResolveIssuer.
|
||||||
|
func (b Token) SigningKeyBytes() []byte {
|
||||||
|
if b.sigSet {
|
||||||
|
return b.sig.GetKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 SigningKeyBytes.
|
||||||
|
func ResolveIssuer(b Token) (usr user.ID) {
|
||||||
|
binKey := b.SigningKeyBytes()
|
||||||
|
|
||||||
|
if len(binKey) != 0 {
|
||||||
|
var key neofsecdsa.PublicKey
|
||||||
|
if key.Decode(binKey) == nil {
|
||||||
|
user.IDFromKey(&usr, ecdsa.PublicKey(key))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// sanityCheck if bearer token is ready to be issued.
|
|
||||||
func sanityCheck(b *Token) error {
|
|
||||||
v2 := (*acl.BearerToken)(b)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case v2.GetBody() == nil:
|
|
||||||
return errNilBearerTokenBody
|
|
||||||
case v2.GetBody().GetEACL() == nil:
|
|
||||||
return errNilBearerTokenEACL
|
|
||||||
}
|
|
||||||
|
|
||||||
// consider checking ContainerEACL sanity there, lifetime correctness, etc.
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal marshals Token into a canonical NeoFS binary format (proto3
|
|
||||||
// with direct field order).
|
|
||||||
//
|
|
||||||
// See also Unmarshal.
|
|
||||||
func (b Token) Marshal() []byte {
|
|
||||||
return (*acl.BearerToken)(&b).StableMarshal(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmarshal unmarshals Token from canonical NeoFS binary format (proto3
|
|
||||||
// with direct field order).
|
|
||||||
//
|
|
||||||
// See also Marshal.
|
|
||||||
func (b *Token) Unmarshal(data []byte) error {
|
|
||||||
v2 := (*acl.BearerToken)(b)
|
|
||||||
return v2.Unmarshal(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON encodes Token to protobuf JSON format.
|
|
||||||
//
|
|
||||||
// See also UnmarshalJSON.
|
|
||||||
func (b Token) MarshalJSON() ([]byte, error) {
|
|
||||||
v2 := (acl.BearerToken)(b)
|
|
||||||
return v2.MarshalJSON()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON decodes Token from protobuf JSON format.
|
|
||||||
//
|
|
||||||
// See also MarshalJSON.
|
|
||||||
func (b *Token) UnmarshalJSON(data []byte) error {
|
|
||||||
v2 := (*acl.BearerToken)(b)
|
|
||||||
return v2.UnmarshalJSON(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b Token) isEmpty() bool {
|
|
||||||
v2token := (acl.BearerToken)(b)
|
|
||||||
return v2token.GetBody() == nil && v2token.GetSignature() == nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,58 +1,390 @@
|
||||||
package bearer_test
|
package bearer_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/acl"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
||||||
tokentest "github.com/nspcc-dev/neofs-sdk-go/bearer/test"
|
bearertest "github.com/nspcc-dev/neofs-sdk-go/bearer/test"
|
||||||
|
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
||||||
|
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
|
||||||
|
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||||
|
eacltest "github.com/nspcc-dev/neofs-sdk-go/eacl/test"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
|
usertest "github.com/nspcc-dev/neofs-sdk-go/user/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBearerToken_Issuer(t *testing.T) {
|
// compares binary representations of two eacl.Table instances.
|
||||||
var bearerToken bearer.Token
|
func isEqualEACLTables(t1, t2 eacl.Table) bool {
|
||||||
|
d1, err := t1.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("non signed token", func(t *testing.T) {
|
d2, err := t2.Marshal()
|
||||||
_, ok := bearerToken.Issuer()
|
if err != nil {
|
||||||
require.False(t, ok)
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes.Equal(d1, d2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToken_SetEACLTable(t *testing.T) {
|
||||||
|
var val bearer.Token
|
||||||
|
var m acl.BearerToken
|
||||||
|
filled := bearertest.Token()
|
||||||
|
|
||||||
|
val.WriteToV2(&m)
|
||||||
|
require.Zero(t, m.GetBody())
|
||||||
|
|
||||||
|
val2 := filled
|
||||||
|
|
||||||
|
require.NoError(t, val2.Unmarshal(val.Marshal()))
|
||||||
|
require.Zero(t, val2.EACLTable())
|
||||||
|
|
||||||
|
val2 = filled
|
||||||
|
|
||||||
|
jd, err := val.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.NoError(t, val2.UnmarshalJSON(jd))
|
||||||
|
require.Zero(t, val2.EACLTable())
|
||||||
|
|
||||||
|
// set value
|
||||||
|
|
||||||
|
eaclTable := *eacltest.Table()
|
||||||
|
|
||||||
|
val.SetEACLTable(eaclTable)
|
||||||
|
require.True(t, isEqualEACLTables(eaclTable, val.EACLTable()))
|
||||||
|
|
||||||
|
val.WriteToV2(&m)
|
||||||
|
eaclTableV2 := eaclTable.ToV2()
|
||||||
|
require.Equal(t, eaclTableV2, m.GetBody().GetEACL())
|
||||||
|
|
||||||
|
val2 = filled
|
||||||
|
|
||||||
|
require.NoError(t, val2.Unmarshal(val.Marshal()))
|
||||||
|
require.True(t, isEqualEACLTables(eaclTable, val.EACLTable()))
|
||||||
|
|
||||||
|
val2 = filled
|
||||||
|
|
||||||
|
jd, err = val.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.NoError(t, val2.UnmarshalJSON(jd))
|
||||||
|
require.True(t, isEqualEACLTables(eaclTable, val.EACLTable()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToken_ForUser(t *testing.T) {
|
||||||
|
var val bearer.Token
|
||||||
|
var m acl.BearerToken
|
||||||
|
filled := bearertest.Token()
|
||||||
|
|
||||||
|
val.WriteToV2(&m)
|
||||||
|
require.Zero(t, m.GetBody())
|
||||||
|
|
||||||
|
val2 := filled
|
||||||
|
|
||||||
|
require.NoError(t, val2.Unmarshal(val.Marshal()))
|
||||||
|
|
||||||
|
val2.WriteToV2(&m)
|
||||||
|
require.Zero(t, m.GetBody())
|
||||||
|
|
||||||
|
val2 = filled
|
||||||
|
|
||||||
|
jd, err := val.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.NoError(t, val2.UnmarshalJSON(jd))
|
||||||
|
|
||||||
|
val2.WriteToV2(&m)
|
||||||
|
require.Zero(t, m.GetBody())
|
||||||
|
|
||||||
|
// set value
|
||||||
|
usr := *usertest.ID()
|
||||||
|
|
||||||
|
var usrV2 refs.OwnerID
|
||||||
|
usr.WriteToV2(&usrV2)
|
||||||
|
|
||||||
|
val.ForUser(usr)
|
||||||
|
|
||||||
|
val.WriteToV2(&m)
|
||||||
|
require.Equal(t, usrV2, *m.GetBody().GetOwnerID())
|
||||||
|
|
||||||
|
val2 = filled
|
||||||
|
|
||||||
|
require.NoError(t, val2.Unmarshal(val.Marshal()))
|
||||||
|
|
||||||
|
val2.WriteToV2(&m)
|
||||||
|
require.Equal(t, usrV2, *m.GetBody().GetOwnerID())
|
||||||
|
|
||||||
|
val2 = filled
|
||||||
|
|
||||||
|
jd, err = val.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.NoError(t, val2.UnmarshalJSON(jd))
|
||||||
|
|
||||||
|
val2.WriteToV2(&m)
|
||||||
|
require.Equal(t, usrV2, *m.GetBody().GetOwnerID())
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLifetimeClaim(t *testing.T, setter func(*bearer.Token, uint64), getter func(*acl.BearerToken) uint64) {
|
||||||
|
var val bearer.Token
|
||||||
|
var m acl.BearerToken
|
||||||
|
filled := bearertest.Token()
|
||||||
|
|
||||||
|
val.WriteToV2(&m)
|
||||||
|
require.Zero(t, m.GetBody())
|
||||||
|
|
||||||
|
val2 := filled
|
||||||
|
|
||||||
|
require.NoError(t, val2.Unmarshal(val.Marshal()))
|
||||||
|
|
||||||
|
val2.WriteToV2(&m)
|
||||||
|
require.Zero(t, m.GetBody())
|
||||||
|
|
||||||
|
val2 = filled
|
||||||
|
|
||||||
|
jd, err := val.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.NoError(t, val2.UnmarshalJSON(jd))
|
||||||
|
|
||||||
|
val2.WriteToV2(&m)
|
||||||
|
require.Zero(t, m.GetBody())
|
||||||
|
|
||||||
|
// set value
|
||||||
|
exp := rand.Uint64()
|
||||||
|
|
||||||
|
setter(&val, exp)
|
||||||
|
|
||||||
|
val.WriteToV2(&m)
|
||||||
|
require.Equal(t, exp, getter(&m))
|
||||||
|
|
||||||
|
val2 = filled
|
||||||
|
|
||||||
|
require.NoError(t, val2.Unmarshal(val.Marshal()))
|
||||||
|
|
||||||
|
val2.WriteToV2(&m)
|
||||||
|
require.Equal(t, exp, getter(&m))
|
||||||
|
|
||||||
|
val2 = filled
|
||||||
|
|
||||||
|
jd, err = val.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.NoError(t, val2.UnmarshalJSON(jd))
|
||||||
|
|
||||||
|
val2.WriteToV2(&m)
|
||||||
|
require.Equal(t, exp, getter(&m))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToken_SetLifetime(t *testing.T) {
|
||||||
|
t.Run("iat", func(t *testing.T) {
|
||||||
|
testLifetimeClaim(t, (*bearer.Token).SetIat, func(token *acl.BearerToken) uint64 {
|
||||||
|
return token.GetBody().GetLifetime().GetIat()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("signed token", func(t *testing.T) {
|
t.Run("nbf", func(t *testing.T) {
|
||||||
p, err := keys.NewPrivateKey()
|
testLifetimeClaim(t, (*bearer.Token).SetNbf, func(token *acl.BearerToken) uint64 {
|
||||||
require.NoError(t, err)
|
return token.GetBody().GetLifetime().GetNbf()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
var id user.ID
|
t.Run("exp", func(t *testing.T) {
|
||||||
user.IDFromKey(&id, p.PrivateKey.PublicKey)
|
testLifetimeClaim(t, (*bearer.Token).SetExp, func(token *acl.BearerToken) uint64 {
|
||||||
|
return token.GetBody().GetLifetime().GetExp()
|
||||||
bearerToken.SetEACLTable(*eacl.NewTable())
|
})
|
||||||
require.NoError(t, bearerToken.Sign(p.PrivateKey))
|
|
||||||
issuer, ok := bearerToken.Issuer()
|
|
||||||
require.True(t, ok)
|
|
||||||
require.True(t, id.Equals(issuer))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFilterEncoding(t *testing.T) {
|
func TestToken_InvalidAt(t *testing.T) {
|
||||||
f := tokentest.Token()
|
var val bearer.Token
|
||||||
|
|
||||||
t.Run("binary", func(t *testing.T) {
|
require.True(t, val.InvalidAt(0))
|
||||||
data := f.Marshal()
|
require.True(t, val.InvalidAt(1))
|
||||||
|
|
||||||
var f2 bearer.Token
|
val.SetIat(1)
|
||||||
require.NoError(t, f2.Unmarshal(data))
|
val.SetNbf(2)
|
||||||
|
val.SetExp(4)
|
||||||
|
|
||||||
require.Equal(t, f, f2)
|
require.True(t, val.InvalidAt(0))
|
||||||
})
|
require.True(t, val.InvalidAt(1))
|
||||||
|
require.False(t, val.InvalidAt(2))
|
||||||
t.Run("json", func(t *testing.T) {
|
require.False(t, val.InvalidAt(3))
|
||||||
data, err := f.MarshalJSON()
|
require.True(t, val.InvalidAt(4))
|
||||||
require.NoError(t, err)
|
require.True(t, val.InvalidAt(5))
|
||||||
|
}
|
||||||
var d2 bearer.Token
|
|
||||||
require.NoError(t, d2.UnmarshalJSON(data))
|
func TestToken_AssertContainer(t *testing.T) {
|
||||||
|
var val bearer.Token
|
||||||
require.Equal(t, f, d2)
|
cnr := cidtest.ID()
|
||||||
})
|
|
||||||
|
require.True(t, val.AssertContainer(cnr))
|
||||||
|
|
||||||
|
eaclTable := *eacltest.Table()
|
||||||
|
|
||||||
|
eaclTable.SetCID(cidtest.ID())
|
||||||
|
val.SetEACLTable(eaclTable)
|
||||||
|
require.False(t, val.AssertContainer(cnr))
|
||||||
|
|
||||||
|
eaclTable.SetCID(cnr)
|
||||||
|
val.SetEACLTable(eaclTable)
|
||||||
|
require.True(t, val.AssertContainer(cnr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToken_AssertUser(t *testing.T) {
|
||||||
|
var val bearer.Token
|
||||||
|
usr := *usertest.ID()
|
||||||
|
|
||||||
|
require.True(t, val.AssertUser(usr))
|
||||||
|
|
||||||
|
val.ForUser(*usertest.ID())
|
||||||
|
require.False(t, val.AssertUser(usr))
|
||||||
|
|
||||||
|
val.ForUser(usr)
|
||||||
|
require.True(t, val.AssertUser(usr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToken_Sign(t *testing.T) {
|
||||||
|
var val bearer.Token
|
||||||
|
|
||||||
|
require.False(t, val.VerifySignature())
|
||||||
|
|
||||||
|
k, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
key := k.PrivateKey
|
||||||
|
val = bearertest.Token()
|
||||||
|
|
||||||
|
require.NoError(t, val.Sign(key))
|
||||||
|
|
||||||
|
require.True(t, val.VerifySignature())
|
||||||
|
|
||||||
|
var m acl.BearerToken
|
||||||
|
val.WriteToV2(&m)
|
||||||
|
|
||||||
|
require.NotZero(t, m.GetSignature().GetKey())
|
||||||
|
require.NotZero(t, m.GetSignature().GetSign())
|
||||||
|
|
||||||
|
val2 := bearertest.Token()
|
||||||
|
|
||||||
|
require.NoError(t, val2.Unmarshal(val.Marshal()))
|
||||||
|
require.True(t, val2.VerifySignature())
|
||||||
|
|
||||||
|
jd, err := val.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
val2 = bearertest.Token()
|
||||||
|
require.NoError(t, val2.UnmarshalJSON(jd))
|
||||||
|
require.True(t, val2.VerifySignature())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToken_ReadFromV2(t *testing.T) {
|
||||||
|
var val bearer.Token
|
||||||
|
var m acl.BearerToken
|
||||||
|
|
||||||
|
require.Error(t, val.ReadFromV2(m))
|
||||||
|
|
||||||
|
var body acl.BearerTokenBody
|
||||||
|
m.SetBody(&body)
|
||||||
|
|
||||||
|
require.Error(t, val.ReadFromV2(m))
|
||||||
|
|
||||||
|
eaclTable := eacltest.Table().ToV2()
|
||||||
|
body.SetEACL(eaclTable)
|
||||||
|
|
||||||
|
require.Error(t, val.ReadFromV2(m))
|
||||||
|
|
||||||
|
var lifetime acl.TokenLifetime
|
||||||
|
body.SetLifetime(&lifetime)
|
||||||
|
|
||||||
|
require.Error(t, val.ReadFromV2(m))
|
||||||
|
|
||||||
|
const iat, nbf, exp = 1, 2, 3
|
||||||
|
lifetime.SetIat(iat)
|
||||||
|
lifetime.SetNbf(nbf)
|
||||||
|
lifetime.SetExp(exp)
|
||||||
|
|
||||||
|
body.SetLifetime(&lifetime)
|
||||||
|
|
||||||
|
require.Error(t, val.ReadFromV2(m))
|
||||||
|
|
||||||
|
var sig refs.Signature
|
||||||
|
m.SetSignature(&sig)
|
||||||
|
|
||||||
|
require.NoError(t, val.ReadFromV2(m))
|
||||||
|
|
||||||
|
var m2 acl.BearerToken
|
||||||
|
|
||||||
|
val.WriteToV2(&m2)
|
||||||
|
require.Equal(t, m, m2)
|
||||||
|
|
||||||
|
usr, usr2 := *usertest.ID(), *usertest.ID()
|
||||||
|
|
||||||
|
require.True(t, val.AssertUser(usr))
|
||||||
|
require.True(t, val.AssertUser(usr2))
|
||||||
|
|
||||||
|
var usrV2 refs.OwnerID
|
||||||
|
usr.WriteToV2(&usrV2)
|
||||||
|
|
||||||
|
body.SetOwnerID(&usrV2)
|
||||||
|
|
||||||
|
require.NoError(t, val.ReadFromV2(m))
|
||||||
|
|
||||||
|
val.WriteToV2(&m2)
|
||||||
|
require.Equal(t, m, m2)
|
||||||
|
|
||||||
|
require.True(t, val.AssertUser(usr))
|
||||||
|
require.False(t, val.AssertUser(usr2))
|
||||||
|
|
||||||
|
k, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
signer := neofsecdsa.Signer(k.PrivateKey)
|
||||||
|
|
||||||
|
var s neofscrypto.Signature
|
||||||
|
|
||||||
|
require.NoError(t, s.Calculate(signer, body.StableMarshal(nil)))
|
||||||
|
|
||||||
|
s.WriteToV2(&sig)
|
||||||
|
|
||||||
|
require.NoError(t, val.ReadFromV2(m))
|
||||||
|
require.True(t, val.VerifySignature())
|
||||||
|
require.Equal(t, sig.GetKey(), val.SigningKeyBytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveIssuer(t *testing.T) {
|
||||||
|
k, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var val bearer.Token
|
||||||
|
|
||||||
|
require.Zero(t, bearer.ResolveIssuer(val))
|
||||||
|
|
||||||
|
var m acl.BearerToken
|
||||||
|
|
||||||
|
var sig refs.Signature
|
||||||
|
sig.SetKey([]byte("invalid key"))
|
||||||
|
|
||||||
|
m.SetSignature(&sig)
|
||||||
|
|
||||||
|
require.NoError(t, val.Unmarshal(m.StableMarshal(nil)))
|
||||||
|
|
||||||
|
require.Zero(t, bearer.ResolveIssuer(val))
|
||||||
|
|
||||||
|
require.NoError(t, val.Sign(k.PrivateKey))
|
||||||
|
|
||||||
|
var usr user.ID
|
||||||
|
user.IDFromKey(&usr, k.PrivateKey.PublicKey)
|
||||||
|
|
||||||
|
require.Equal(t, usr, bearer.ResolveIssuer(val))
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,10 @@ import (
|
||||||
//
|
//
|
||||||
// Resulting token is unsigned.
|
// Resulting token is unsigned.
|
||||||
func Token() (t bearer.Token) {
|
func Token() (t bearer.Token) {
|
||||||
t.SetExpiration(3)
|
t.SetExp(3)
|
||||||
t.SetNotBefore(2)
|
t.SetNbf(2)
|
||||||
t.SetIssuedAt(1)
|
t.SetIat(1)
|
||||||
t.SetOwnerID(*usertest.ID())
|
t.ForUser(*usertest.ID())
|
||||||
t.SetEACLTable(*eacltest.Table())
|
t.SetEACLTable(*eacltest.Table())
|
||||||
|
|
||||||
return t
|
return t
|
||||||
|
|
Loading…
Reference in a new issue