diff --git a/go.mod b/go.mod index 6619a037..ae67a9a6 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/golang/protobuf v1.4.2 // indirect github.com/klauspost/compress v1.13.4 github.com/minio/highwayhash v1.0.1 - github.com/nats-io/jwt/v2 v2.2.0 + github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 github.com/nats-io/nats.go v1.13.1-0.20211122170419-d7c1d78a50fc github.com/nats-io/nkeys v0.3.0 github.com/nats-io/nuid v1.0.1 diff --git a/go.sum b/go.sum index 5136dc1b..cb6bbf29 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEE github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0= github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/nats-io/jwt/v2 v2.2.0 h1:Yg/4WFK6vsqMudRg91eBb7Dh6XeVcDMPHycDE8CfltE= -github.com/nats-io/jwt/v2 v2.2.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= +github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 h1:vU9tpM3apjYlLLeY23zRWJ9Zktr5jp+mloR942LEOpY= +github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= github.com/nats-io/nats.go v1.13.1-0.20211122170419-d7c1d78a50fc h1:SHr4MUUZJ/fAC0uSm2OzWOJYsHpapmR86mpw7q1qPXU= github.com/nats-io/nats.go v1.13.1-0.20211122170419-d7c1d78a50fc/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= diff --git a/server/accounts.go b/server/accounts.go index db5d6e52..e2a9ac22 100644 --- a/server/accounts.go +++ b/server/accounts.go @@ -3195,10 +3195,11 @@ func (s *Server) updateAccountClaimsWithRefresh(a *Account, ac *jwt.AccountClaim if ac.Limits.JetStreamLimits.DiskStorage != 0 || ac.Limits.JetStreamLimits.MemoryStorage != 0 { // JetStreamAccountLimits and jwt.JetStreamLimits use same value for unlimited a.jsLimits = &JetStreamAccountLimits{ - MaxMemory: ac.Limits.JetStreamLimits.MemoryStorage, - MaxStore: ac.Limits.JetStreamLimits.DiskStorage, - MaxStreams: int(ac.Limits.JetStreamLimits.Streams), - MaxConsumers: int(ac.Limits.JetStreamLimits.Consumer), + MaxMemory: ac.Limits.JetStreamLimits.MemoryStorage, + MaxStore: ac.Limits.JetStreamLimits.DiskStorage, + MaxStreams: int(ac.Limits.JetStreamLimits.Streams), + MaxConsumers: int(ac.Limits.JetStreamLimits.Consumer), + MaxBytesRequired: ac.Limits.JetStreamLimits.MaxBytesRequired, } } else if a.jsLimits != nil { // covers failed update followed by disable diff --git a/server/jwt_test.go b/server/jwt_test.go index 9c0f395a..a0a42386 100644 --- a/server/jwt_test.go +++ b/server/jwt_test.go @@ -4259,7 +4259,7 @@ func TestJWTJetStreamLimits(t *testing.T) { sysKp.Seed() sysCreds := genCredsFile(t, sysUserJwt, sysUSeed) // limits to apply and check - limits1 := jwt.JetStreamLimits{MemoryStorage: 1024 * 1024, DiskStorage: 2048 * 1024, Streams: 1, Consumer: 2} + limits1 := jwt.JetStreamLimits{MemoryStorage: 1024 * 1024, DiskStorage: 2048 * 1024, Streams: 1, Consumer: 2, MaxBytesRequired: true} // has valid limits that would fail when incorrectly applied twice limits2 := jwt.JetStreamLimits{MemoryStorage: 4096 * 1024, DiskStorage: 8192 * 1024, Streams: 3, Consumer: 4} // limits exceeding actual configured value of DiskStorage diff --git a/vendor/github.com/nats-io/jwt/v2/account_claims.go b/vendor/github.com/nats-io/jwt/v2/account_claims.go index 04065b6a..8568da16 100644 --- a/vendor/github.com/nats-io/jwt/v2/account_claims.go +++ b/vendor/github.com/nats-io/jwt/v2/account_claims.go @@ -51,15 +51,16 @@ func (n *NatsLimits) IsUnlimited() bool { } type JetStreamLimits struct { - MemoryStorage int64 `json:"mem_storage,omitempty"` // Max number of bytes stored in memory across all streams. (0 means disabled) - DiskStorage int64 `json:"disk_storage,omitempty"` // Max number of bytes stored on disk across all streams. (0 means disabled) - Streams int64 `json:"streams,omitempty"` // Max number of streams - Consumer int64 `json:"consumer,omitempty"` // Max number of consumer + MemoryStorage int64 `json:"mem_storage,omitempty"` // Max number of bytes stored in memory across all streams. (0 means disabled) + DiskStorage int64 `json:"disk_storage,omitempty"` // Max number of bytes stored on disk across all streams. (0 means disabled) + Streams int64 `json:"streams,omitempty"` // Max number of streams + Consumer int64 `json:"consumer,omitempty"` // Max number of consumers + MaxBytesRequired bool `json:"max_bytes_required,omitempty"` // Max bytes required by all Streams } // IsUnlimited returns true if all limits are unlimited func (j *JetStreamLimits) IsUnlimited() bool { - return *j == JetStreamLimits{NoLimit, NoLimit, NoLimit, NoLimit} + return *j == JetStreamLimits{NoLimit, NoLimit, NoLimit, NoLimit, false} } // OperatorLimits are used to limit access by an account @@ -188,7 +189,7 @@ func NewAccountClaims(subject string) *AccountClaims { c.Limits = OperatorLimits{ NatsLimits{NoLimit, NoLimit, NoLimit}, AccountLimits{NoLimit, NoLimit, true, NoLimit, NoLimit}, - JetStreamLimits{0, 0, 0, 0}} + JetStreamLimits{0, 0, 0, 0, false}} c.Subject = subject c.Mappings = Mapping{} return c diff --git a/vendor/github.com/nats-io/jwt/v2/creds_utils.go b/vendor/github.com/nats-io/jwt/v2/creds_utils.go index c532c887..94312ff5 100644 --- a/vendor/github.com/nats-io/jwt/v2/creds_utils.go +++ b/vendor/github.com/nats-io/jwt/v2/creds_utils.go @@ -21,6 +21,7 @@ import ( "fmt" "regexp" "strings" + "time" "github.com/nats-io/nkeys" ) @@ -216,3 +217,49 @@ func ParseDecoratedUserNKey(contents []byte) (nkeys.KeyPair, error) { } return kp, nil } + +// IssueUserJWT takes an account scoped signing key, account id, and use public key (and optionally a user's name, an expiration duration and tags) and returns a valid signed JWT. +// The scopedSigningKey, is a mandatory account scoped signing nkey pair to sign the generated jwt (note that it _must_ be a signing key attached to the account (and a _scoped_ signing key), not the account's private (seed) key). +// The accountId, is a mandatory public account nkey. Will return error when not set or not account nkey. +// The publicUserKey, is a mandatory public user nkey. Will return error when not set or not user nkey. +// The name, is an optional human-readable name. When absent, default to publicUserKey. +// The expirationDuration, is an optional but recommended duration, when the generated jwt needs to expire. If not set, JWT will not expire. +// The tags, is an optional list of tags to be included in the JWT. +// +// Returns: +// string, resulting jwt. +// error, when issues arose. +func IssueUserJWT(scopedSigningKey nkeys.KeyPair, accountId string, publicUserKey string, name string, expirationDuration time.Duration, tags ...string) (string, error) { + + if !nkeys.IsValidPublicAccountKey(accountId) { + return "", errors.New("issueUserJWT requires an account key for the accountId parameter, but got " + nkeys.Prefix(accountId).String()) + } + + if !nkeys.IsValidPublicUserKey(publicUserKey) { + return "", errors.New("issueUserJWT requires an account key for the publicUserKey parameter, but got " + nkeys.Prefix(publicUserKey).String()) + } + + claim := NewUserClaims(publicUserKey) + claim.SetScoped(true) + + if expirationDuration != 0 { + claim.Expires = time.Now().Add(expirationDuration).UTC().Unix() + } + + claim.IssuerAccount = accountId + if name != "" { + claim.Name = name + } else { + claim.Name = publicUserKey + } + + claim.Subject = publicUserKey + claim.Tags = tags + + encoded, err := claim.Encode(scopedSigningKey) + if err != nil { + return "", errors.New("err encoding claim " + err.Error()) + } + + return encoded, nil +} diff --git a/vendor/github.com/nats-io/jwt/v2/decoder_account.go b/vendor/github.com/nats-io/jwt/v2/decoder_account.go index 607d9840..820982c9 100644 --- a/vendor/github.com/nats-io/jwt/v2/decoder_account.go +++ b/vendor/github.com/nats-io/jwt/v2/decoder_account.go @@ -73,7 +73,7 @@ func (oa v1AccountClaims) migrateV1() (*AccountClaims, error) { a.Account.Exports = oa.v1NatsAccount.Exports a.Account.Limits.AccountLimits = oa.v1NatsAccount.Limits.AccountLimits a.Account.Limits.NatsLimits = oa.v1NatsAccount.Limits.NatsLimits - a.Account.Limits.JetStreamLimits = JetStreamLimits{0, 0, 0, 0} + a.Account.Limits.JetStreamLimits = JetStreamLimits{0, 0, 0, 0, false} a.Account.SigningKeys = make(SigningKeys) for _, v := range oa.SigningKeys { a.Account.SigningKeys.Add(v) diff --git a/vendor/modules.txt b/vendor/modules.txt index c78f5afe..5a208311 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -6,7 +6,7 @@ github.com/klauspost/compress/s2 # github.com/minio/highwayhash v1.0.1 ## explicit github.com/minio/highwayhash -# github.com/nats-io/jwt/v2 v2.2.0 +# github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 ## explicit github.com/nats-io/jwt/v2 # github.com/nats-io/nats.go v1.13.1-0.20211122170419-d7c1d78a50fc