Skip to content

Commit

Permalink
Merge pull request #1052 from ripienaar/auth_tags
Browse files Browse the repository at this point in the history
Support tags on operators, accounts and users
  • Loading branch information
ripienaar committed May 2, 2024
2 parents 926dac6 + ef59d3b commit e45eb20
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 12 deletions.
33 changes: 26 additions & 7 deletions cli/auth_account_command.go
Expand Up @@ -97,6 +97,8 @@ type authAccountCommand struct {
importAccount string
bucketName string
prefix string
tags []string
rmTags []string
}

func configureAuthAccountCommand(auth commandHost) {
Expand All @@ -105,23 +107,27 @@ func configureAuthAccountCommand(auth commandHost) {
acct := auth.Command("account", "Manage NATS Accounts").Alias("a").Alias("acct").Alias("act")

addCreateFlags := func(f *fisk.CmdClause, edit bool) {
f.Flag("expiry", "How long this account should be valid for as a duration").PlaceHolder("DURATION").DurationVar(&c.expiry)
f.Flag("bearer", "Allows bearer tokens").Default("false").IsSetByUser(&c.bearerAllowedIsSet).BoolVar(&c.bearerAllowed)
f.Flag("subscriptions", "Maximum allowed subscriptions").Default("-1").IsSetByUser(&c.maxSubIsSet).Int64Var(&c.maxSubs)
f.Flag("connections", "Maximum allowed connections").Default("-1").IsSetByUser(&c.maxConnsIsSet).Int64Var(&c.maxConns)
f.Flag("payload", "Maximum allowed payload").PlaceHolder("BYTES").Default("-1").StringVar(&c.maxPayloadString)
f.Flag("leafnodes", "Maximum allowed Leafnode connections").Default("-1").IsSetByUser(&c.maxLeafNodesIsSet).Int64Var(&c.maxLeafnodes)
f.Flag("imports", "Maximum allowed imports").Default("-1").IsSetByUser(&c.maxImportsIsSet).Int64Var(&c.maxImports)
f.Flag("expiry", "How long this account should be valid for as a duration").PlaceHolder("DURATION").DurationVar(&c.expiry)
f.Flag("exports", "Maximum allowed exports").Default("-1").IsSetByUser(&c.maxExportsIsSet).Int64Var(&c.maxExports)
f.Flag("imports", "Maximum allowed imports").Default("-1").IsSetByUser(&c.maxImportsIsSet).Int64Var(&c.maxImports)
f.Flag("jetstream", "Enables JetStream").Default("false").IsSetByUser(&c.jetStreamIsSet).BoolVar(&c.jetStream)
f.Flag("js-streams", "Sets the maximum Streams the account can have").Default("-1").IsSetByUser(&c.maxStreamsIsSet).Int64Var(&c.maxStreams)
f.Flag("js-consumers", "Sets the maximum Consumers the account can have").Default("-1").IsSetByUser(&c.maxConsumersIsSet).Int64Var(&c.maxConsumers)
f.Flag("js-disk", "Sets a Disk Storage quota").PlaceHolder("BYTES").StringVar(&c.storeMaxString)
f.Flag("js-disk-stream", "Sets the maximum size a Disk Storage stream may be").PlaceHolder("BYTES").Default("-1").StringVar(&c.storeMaxStreamString)
f.Flag("js-max-pending", "Default Max Ack Pending for Tier 0 limits").PlaceHolder("MESSAGES").IsSetByUser(&c.maxAckPendingIsSet).Int64Var(&c.maxAckPending)
f.Flag("js-memory", "Sets a Memory Storage quota").PlaceHolder("BYTES").StringVar(&c.memMaxString)
f.Flag("js-memory-stream", "Sets the maximum size a Memory Storage stream may be").PlaceHolder("BYTES").Default("-1").StringVar(&c.memMaxStreamString)
f.Flag("js-max-pending", "Default Max Ack Pending for Tier 0 limits").PlaceHolder("MESSAGES").IsSetByUser(&c.maxAckPendingIsSet).Int64Var(&c.maxAckPending)
f.Flag("js-stream-size-required", "Requires Streams to have a maximum size declared").IsSetByUser(&c.streamSizeRequiredIsSet).UnNegatableBoolVar(&c.streamSizeRequired)
f.Flag("js-streams", "Sets the maximum Streams the account can have").Default("-1").IsSetByUser(&c.maxStreamsIsSet).Int64Var(&c.maxStreams)
f.Flag("leafnodes", "Maximum allowed Leafnode connections").Default("-1").IsSetByUser(&c.maxLeafNodesIsSet).Int64Var(&c.maxLeafnodes)
f.Flag("payload", "Maximum allowed payload").PlaceHolder("BYTES").Default("-1").StringVar(&c.maxPayloadString)
f.Flag("subscriptions", "Maximum allowed subscriptions").Default("-1").IsSetByUser(&c.maxSubIsSet).Int64Var(&c.maxSubs)
f.Flag("tags", "Tags to assign to this Account").StringsVar(&c.tags)
if edit {
f.Flag("no-tags", "Tags to remove from this Account").StringsVar(&c.rmTags)
}
}

add := acct.Command("add", "Adds a new Account").Alias("create").Alias("new").Action(c.addAction)
Expand Down Expand Up @@ -648,6 +654,11 @@ func (c *authAccountCommand) editAction(_ *fisk.ParseContext) error {
c.bearerAllowed = !limits.DisallowBearer
}

err = au.UpdateTags(acct.Tags(), c.tags, c.rmTags)
if err != nil {
return err
}

if jsEnabled {
if !c.jetStreamIsSet {
c.jetStream = true
Expand Down Expand Up @@ -901,6 +912,11 @@ func (c *authAccountCommand) addAction(_ *fisk.ParseContext) error {
return err
}

err = au.UpdateTags(acct.Tags(), c.tags, c.rmTags)
if err != nil {
return err
}

if !c.defaults {
if c.maxConns == -1 {
c.maxConns, err = askOneInt("Maximum Connections", "-1", "The maximum amount of client connections allowed for this account, set using --connections")
Expand Down Expand Up @@ -978,6 +994,9 @@ func (c *authAccountCommand) showAccount(operator ab.Operator, acct ab.Account)
cols.AddRow("System Account", false)
}
}
if tags, _ := acct.Tags().All(); len(tags) > 0 {
cols.AddStringsAsValue("Tags", tags)
}
cols.AddRow("JetStream", js.IsJetStreamEnabled())
cols.AddRowIf("Expiry", time.Unix(acct.Expiry(), 0), acct.Expiry() > 0)
cols.AddRow("Users", len(acct.Users().List()))
Expand Down
18 changes: 18 additions & 0 deletions cli/auth_operator_command.go
Expand Up @@ -50,6 +50,8 @@ type authOperatorCommand struct {
outputFile string
encKey string
jetstream bool
tags []string
rmTags []string
}

func configureAuthOperatorCommand(auth commandHost) {
Expand All @@ -62,6 +64,7 @@ func configureAuthOperatorCommand(auth commandHost) {
add.Flag("service", "URLs for the Operator services").PlaceHolder("URL").URLListVar(&c.operatorService)
add.Flag("account-server", "URL for the account server").PlaceHolder("URL").URLVar(&c.accountServer)
add.Flag("signing-key", "Creates a signing key for this account").Default("true").BoolVar(&c.createSK)
add.Flag("tags", "Tags to assign to this Operator").StringsVar(&c.tags)

info := op.Command("info", "Show Operator information").Alias("i").Alias("show").Alias("view").Action(c.infoAction)
info.Arg("name", "Operator to view").StringVar(&c.operatorName)
Expand All @@ -73,6 +76,8 @@ func configureAuthOperatorCommand(auth commandHost) {
edit.Arg("name", "Operator to edit").StringVar(&c.operatorName)
edit.Flag("account-server", "URL for the Account Server").IsSetByUser(&c.accountServerIsSet).PlaceHolder("URL").URLVar(&c.accountServer)
edit.Flag("service", "URLs for the Operator Services").IsSetByUser(&c.operatorServiceIsSet).PlaceHolder("URL").URLListVar(&c.operatorService)
edit.Flag("tags", "Tags to add to this Operator").StringsVar(&c.tags)
edit.Flag("no-tags", "Tags to remove from the Operator").StringsVar(&c.rmTags)

imp := op.Command("import", "Imports an operator").Action(c.importAction)
imp.Arg("token", "The JWT file containing the account to import").Required().PlaceHolder("JWT").ExistingFileVar(&c.tokenFile)
Expand Down Expand Up @@ -346,6 +351,11 @@ func (c *authOperatorCommand) editAction(_ *fisk.ParseContext) error {
}
}

err = au.UpdateTags(operator.Tags(), c.tags, c.rmTags)
if err != nil {
return err
}

err = auth.Commit()
if err != nil {
return err
Expand Down Expand Up @@ -531,6 +541,11 @@ func (c *authOperatorCommand) addAction(_ *fisk.ParseContext) error {
return err
}

err = au.UpdateTags(operator.Tags(), c.tags, c.rmTags)
if err != nil {
return err
}

if c.operatorService != nil {
list := []string{}
for _, s := range c.operatorService {
Expand Down Expand Up @@ -586,6 +601,9 @@ func (c *authOperatorCommand) showOperator(operator ab.Operator) (string, error)
cols.AddSectionTitle("Configuration")
cols.AddRow("Name", operator.Name())
cols.AddRow("Subject", operator.Subject())
if tags, _ := operator.Tags().All(); len(tags) > 0 {
cols.AddStringsAsValue("Tags", tags)
}
cols.AddRowIf("Service URL(s)", operator.OperatorServiceURLs(), len(operator.OperatorServiceURLs()) > 0)
cols.AddRowIfNotEmpty("Account Server", operator.AccountServerURL())
cols.AddRow("Accounts", len(operator.Accounts().List()))
Expand Down
26 changes: 22 additions & 4 deletions cli/auth_user_command.go
Expand Up @@ -45,6 +45,8 @@ type authUserCommand struct {
pubDeny []string
subDeny []string
subAllow []string
tags []string
rmTags []string
listNames bool
force bool
credFile string
Expand All @@ -58,15 +60,19 @@ func configureAuthUserCommand(auth commandHost) {
user := auth.Command("user", "Manage Account Users").Alias("u").Alias("usr").Alias("users")

addCreateFlags := func(f *fisk.CmdClause, edit bool) {
f.Flag("locale", "Sets the locale for the user connection").StringVar(&c.userLocale)
f.Flag("bearer", "Enables the use of bearer tokens").BoolVar(&c.bearerAllowed)
f.Flag("data", "Maximum message data size to allow").Default("-1").Int64Var(&c.maxData)
f.Flag("locale", "Sets the locale for the user connection").StringVar(&c.userLocale)
f.Flag("payload", "Maximum payload size to allow").IsSetByUser(&c.maxPayloadIsSet).Default("1048576").Int64Var(&c.maxPayload)
f.Flag("subscriptions", "Maximum subscription count to allow").IsSetByUser(&c.maxSubsIsSet).Default("-1").Int64Var(&c.maxSubs)
f.Flag("pub-allow", "Allow publishing to a subject").StringsVar(&c.pubAllow)
f.Flag("pub-deny", "Deny publishing to a subject").StringsVar(&c.pubDeny)
f.Flag("sub-allow", "Allow subscribing to a subject").StringsVar(&c.subAllow)
f.Flag("sub-deny", "Deny subscribing to a subject").StringsVar(&c.subDeny)
f.Flag("data", "Maximum message data size to allow").Default("-1").Int64Var(&c.maxData)
f.Flag("subscriptions", "Maximum subscription count to allow").IsSetByUser(&c.maxSubsIsSet).Default("-1").Int64Var(&c.maxSubs)
f.Flag("tags", "Tags to assign to this User").StringsVar(&c.tags)
if edit {
f.Flag("no-tags", "Tags to remove from this User").StringsVar(&c.rmTags)
}
}

add := user.Command("add", "Adds a new User").Alias("create").Alias("new").Action(c.addAction)
Expand Down Expand Up @@ -384,6 +390,11 @@ func (c *authUserCommand) addAction(_ *fisk.ParseContext) error {
}
}

err = au.UpdateTags(user.Tags(), c.tags, c.rmTags)
if err != nil {
return err
}

err = c.updateUser(user)
if err != nil {
return err
Expand Down Expand Up @@ -447,6 +458,11 @@ func (c *authUserCommand) updateUser(user ab.User) error {
limits.Sub.Deny = c.subDeny
}

err := au.UpdateTags(user.Tags(), c.tags, c.rmTags)
if err != nil {
return err
}

return user.(*ab.UserData).SetUserPermissionLimits(limits)
}

Expand All @@ -466,9 +482,11 @@ func (c *authUserCommand) showUser(user ab.User, acct ab.Account) (string, error
cols.AddRow("Account", fmt.Sprintf("%s (%s)", acct.Name(), user.IssuerAccount()))
cols.AddRow("Issuer", user.Issuer())
cols.AddRow("Scoped", user.IsScoped())
if tags, _ := user.Tags().All(); len(tags) > 0 {
cols.AddStringsAsValue("Tags", tags)
}

limits := ab.UserLimits(user)

if user.IsScoped() {
scope, err := acct.ScopedSigningKeys().GetScope(user.Issuer())
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -29,7 +29,7 @@ require (
github.com/prometheus/client_golang v1.19.0
github.com/prometheus/common v0.53.0
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
github.com/synadia-io/jwt-auth-builder.go v0.0.0-20240423085918-567b5f89c654
github.com/synadia-io/jwt-auth-builder.go v0.0.0-20240501200458-e2594dc0b29f
github.com/tylertreat/hdrhistogram-writer v0.0.0-20210816161836-2e440612a39f
golang.org/x/crypto v0.22.0
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -151,6 +151,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/synadia-io/jwt-auth-builder.go v0.0.0-20240423085918-567b5f89c654 h1:UTJ3gAbQmRHCW9rqCCx7G2SJKdSA1HyeYmCeHm5Y/5s=
github.com/synadia-io/jwt-auth-builder.go v0.0.0-20240423085918-567b5f89c654/go.mod h1:z+ZENSUrwJFMZstPcEfPAXXVKRibe0iqx0ACG5ikYBg=
github.com/synadia-io/jwt-auth-builder.go v0.0.0-20240501200458-e2594dc0b29f h1:Q0aiLE3DWWmTKK+hTpHhqssOIITnm6YAfQsONcp4Op4=
github.com/synadia-io/jwt-auth-builder.go v0.0.0-20240501200458-e2594dc0b29f/go.mod h1:z+ZENSUrwJFMZstPcEfPAXXVKRibe0iqx0ACG5ikYBg=
github.com/tylertreat/hdrhistogram-writer v0.0.0-20210816161836-2e440612a39f h1:SGznmvCovewbaSgBsHgdThtWsLj5aCLX/3ZXMLd1UD0=
github.com/tylertreat/hdrhistogram-writer v0.0.0-20210816161836-2e440612a39f/go.mod h1:IY84XkhrEJTdHYLNy/zObs8mXuUAp9I65VyarbPSCCY=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
Expand Down
19 changes: 19 additions & 0 deletions internal/auth/auth.go
Expand Up @@ -31,6 +31,25 @@ type UserLimitsManager interface {
SetUserPermissionLimits(limits jwt.UserPermissionLimits) error
}

func UpdateTags(tags ab.Tags, add []string, rm []string) error {
if len(add) > 0 {
err := tags.Add(add...)
if err != nil {
return err
}
}
if len(rm) > 0 {
for _, tag := range rm {
_, err := tags.Remove(tag)
if err != nil {
return err
}
}
}

return nil
}

func SortedAuthNames[list listWithNames](items []list) []string {
var res []string
for _, i := range items {
Expand Down

0 comments on commit e45eb20

Please sign in to comment.