[#108] authmate: Add lifetime for tokens

Signed-off-by: Angira Kekteeva <kira@nspcc.ru>
This commit is contained in:
Angira Kekteeva 2021-06-28 16:20:11 +03:00
parent ce65a47d1b
commit f97739898a
2 changed files with 63 additions and 15 deletions

View file

@ -53,6 +53,7 @@ type (
EACLRules []byte
ContextRules []byte
SessionTkn bool
Lifetime uint64
}
// ObtainSecretOptions contains options for passing to Agent.ObtainSecret method.
@ -62,6 +63,12 @@ type (
}
)
// lifetimeOptions holds NeoFS epochs, iat -- epoch, which a token was issued at, exp -- epoch, when the token expires.
type lifetimeOptions struct {
Iat uint64
Exp uint64
}
type (
issuingResult struct {
AccessKeyID string `json:"access_key_id"`
@ -104,20 +111,42 @@ func (a *Agent) checkContainer(ctx context.Context, cid *cid.ID, friendlyName st
return cid, nil
}
func (a *Agent) getCurrentEpoch(ctx context.Context) (uint64, error) {
if conn, _, err := a.pool.Connection(); err != nil {
return 0, err
} else if networkInfo, err := conn.NetworkInfo(ctx); err != nil {
return 0, err
} else {
return networkInfo.CurrentEpoch(), nil
}
}
// IssueSecret creates an auth token, puts it in the NeoFS network and writes to io.Writer a new secret access key.
func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecretOptions) error {
var (
err error
cid *cid.ID
box *accessbox.AccessBox
lifetime lifetimeOptions
)
lifetime.Iat, err = a.getCurrentEpoch(ctx)
if err != nil {
return err
}
if options.Lifetime >= math.MaxUint64-lifetime.Iat {
lifetime.Exp = math.MaxUint64
} else {
lifetime.Exp = lifetime.Iat + options.Lifetime
}
a.log.Info("check container", zap.Stringer("cid", options.ContainerID))
if cid, err = a.checkContainer(ctx, options.ContainerID, options.ContainerFriendlyName); err != nil {
return err
}
gatesData, err := createTokens(options, cid)
gatesData, err := createTokens(options, lifetime, cid)
if err != nil {
return fmt.Errorf("failed to build bearer token: %w", err)
}
@ -257,7 +286,7 @@ func buildContext(rules []byte) (*session.ContainerContext, error) {
return sessionCtx, nil
}
func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, gateKey *keys.PublicKey) (*token.BearerToken, error) {
func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, lifetime lifetimeOptions, gateKey *keys.PublicKey) (*token.BearerToken, error) {
oid, err := ownerIDFromNeoFSKey(gateKey)
if err != nil {
return nil, err
@ -266,15 +295,15 @@ func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, gateKey *keys.Pub
bearerToken := token.NewBearerToken()
bearerToken.SetEACLTable(table)
bearerToken.SetOwner(oid)
bearerToken.SetLifetime(math.MaxUint64, 0, 0)
bearerToken.SetLifetime(lifetime.Exp, lifetime.Iat, lifetime.Iat)
return bearerToken, bearerToken.SignToken(&key.PrivateKey)
}
func buildBearerTokens(key *keys.PrivateKey, table *eacl.Table, gatesKeys []*keys.PublicKey) ([]*token.BearerToken, error) {
func buildBearerTokens(key *keys.PrivateKey, table *eacl.Table, lifetime lifetimeOptions, gatesKeys []*keys.PublicKey) ([]*token.BearerToken, error) {
bearerTokens := make([]*token.BearerToken, 0, len(gatesKeys))
for _, gateKey := range gatesKeys {
tkn, err := buildBearerToken(key, table, gateKey)
tkn, err := buildBearerToken(key, table, lifetime, gateKey)
if err != nil {
return nil, err
}
@ -283,7 +312,7 @@ func buildBearerTokens(key *keys.PrivateKey, table *eacl.Table, gatesKeys []*key
return bearerTokens, nil
}
func buildSessionToken(key *keys.PrivateKey, oid *owner.ID, ctx *session.ContainerContext, gateKey *keys.PublicKey) (*session.Token, error) {
func buildSessionToken(key *keys.PrivateKey, oid *owner.ID, lifetime lifetimeOptions, ctx *session.ContainerContext, gateKey *keys.PublicKey) (*session.Token, error) {
tok := session.NewToken()
tok.SetContext(ctx)
uid, err := uuid.New().MarshalBinary()
@ -294,13 +323,17 @@ func buildSessionToken(key *keys.PrivateKey, oid *owner.ID, ctx *session.Contain
tok.SetOwnerID(oid)
tok.SetSessionKey(gateKey.Bytes())
tok.SetIat(lifetime.Iat)
tok.SetNbf(lifetime.Iat)
tok.SetExp(lifetime.Exp)
return tok, tok.Sign(&key.PrivateKey)
}
func buildSessionTokens(key *keys.PrivateKey, oid *owner.ID, ctx *session.ContainerContext, gatesKeys []*keys.PublicKey) ([]*session.Token, error) {
func buildSessionTokens(key *keys.PrivateKey, oid *owner.ID, lifetime lifetimeOptions, ctx *session.ContainerContext, gatesKeys []*keys.PublicKey) ([]*session.Token, error) {
sessionTokens := make([]*session.Token, 0, len(gatesKeys))
for _, gateKey := range gatesKeys {
tkn, err := buildSessionToken(key, oid, ctx, gateKey)
tkn, err := buildSessionToken(key, oid, lifetime, ctx, gateKey)
if err != nil {
return nil, err
}
@ -309,14 +342,14 @@ func buildSessionTokens(key *keys.PrivateKey, oid *owner.ID, ctx *session.Contai
return sessionTokens, nil
}
func createTokens(options *IssueSecretOptions, cid *cid.ID) ([]*accessbox.GateData, error) {
func createTokens(options *IssueSecretOptions, lifetime lifetimeOptions, 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)
bearerTokens, err := buildBearerTokens(options.NeoFSKey, table, lifetime, options.GatesPublicKeys)
if err != nil {
return nil, fmt.Errorf("failed to build bearer tokens: %w", err)
}
@ -334,7 +367,7 @@ func createTokens(options *IssueSecretOptions, cid *cid.ID) ([]*accessbox.GateDa
return nil, err
}
sessionTokens, err := buildSessionTokens(options.NeoFSKey, oid, sessionRules, options.GatesPublicKeys)
sessionTokens, err := buildSessionTokens(options.NeoFSKey, oid, lifetime, sessionRules, options.GatesPublicKeys)
if err != nil {
return nil, err
}

View file

@ -25,6 +25,8 @@ import (
const (
poolConnectTimeout = 5 * time.Second
poolRequestTimeout = 5 * time.Second
// a number of 15-second blocks in a month.
defaultLifetime = 172800
)
var (
@ -42,6 +44,7 @@ var (
logEnabledFlag bool
logDebugEnabledFlag bool
sessionTokenFlag bool
lifetimeFlag uint64
)
const (
@ -191,6 +194,13 @@ func issueSecret() *cli.Command {
Destination: &sessionTokenFlag,
Value: false,
},
&cli.Uint64Flag{
Name: "lifetime",
Usage: "Lifetime of tokens in NeoFS epoch (number of blocks in sidechain)",
Required: false,
Destination: &lifetimeFlag,
Value: defaultLifetime,
},
},
Action: func(c *cli.Context) error {
ctx, log := prepare()
@ -222,11 +232,15 @@ func issueSecret() *cli.Command {
for _, key := range gatesPublicKeysFlag.Value() {
gpk, err := keys.NewPublicKeyFromString(key)
if err != nil {
return cli.Exit(fmt.Sprintf("failed to load gate's public key: %s", err), 5)
return cli.Exit(fmt.Sprintf("failed to load gate's public key: %s", err), 4)
}
gatesPublicKeys = append(gatesPublicKeys, gpk)
}
if lifetimeFlag <= 0 {
return cli.Exit(fmt.Sprintf("lifetime must be at least 1, current value: %d", lifetimeFlag), 5)
}
issueSecretOptions := &authmate.IssueSecretOptions{
ContainerID: containerID,
ContainerFriendlyName: containerFriendlyName,
@ -235,6 +249,7 @@ func issueSecret() *cli.Command {
EACLRules: []byte(eaclRulesFlag),
ContextRules: []byte(contextRulesFlag),
SessionTkn: sessionTokenFlag,
Lifetime: lifetimeFlag,
}
if err = agent.IssueSecret(ctx, os.Stdout, issueSecretOptions); err != nil {