diff --git a/accounts.go b/accounts.go index ace12cf..28c4313 100644 --- a/accounts.go +++ b/accounts.go @@ -142,6 +142,43 @@ func (a *AccountData) Limits() AccountLimits { return &accountLimits{data: a} } +func (a *AccountData) SetExternalAuthorizationUser(users []User, accounts []Account, encryption string) error { + if users == nil { + // disable + a.Claim.Authorization.AuthUsers = nil + a.Claim.Authorization.AllowedAccounts = nil + a.Claim.Authorization.XKey = "" + } else { + var ukeys []string + for _, u := range users { + ukeys = append(ukeys, u.Subject()) + } + a.Claim.Authorization.AuthUsers = ukeys + + var akeys []string + for _, a := range accounts { + akeys = append(akeys, a.Subject()) + } + a.Claim.Authorization.AllowedAccounts = akeys + + if encryption != "" { + key, err := KeyFrom(encryption, nkeys.PrefixByteCurve) + if err != nil { + return err + } + a.Claim.Authorization.XKey = key.Public + } else { + a.Claim.Authorization.XKey = "" + } + } + return a.update() +} + +func (a *AccountData) ExternalAuthorization() ([]string, []string, string) { + config := a.Claim.Authorization + return config.AuthUsers, config.AllowedAccounts, config.XKey +} + type exports struct { *AccountData } diff --git a/tests/accounts_test.go b/tests/accounts_test.go index 7fcac89..c1f01d8 100644 --- a/tests/accounts_test.go +++ b/tests/accounts_test.go @@ -2,6 +2,7 @@ package tests import ( "fmt" + "github.com/nats-io/nkeys" "time" "github.com/nats-io/jwt/v2" @@ -871,3 +872,53 @@ func (t *ProviderSuite) Test_TracingContext() { t.NoError(a.SetTracingContext(nil)) t.Nil(a.GetTracingContext()) } + +func (t *ProviderSuite) Test_ExternalAuthorization() { + auth, err := authb.NewAuth(t.Provider) + t.NoError(err) + + a := t.MaybeCreate(auth, "O", "A") + t.NotNil(a) + + external := t.MaybeCreate(auth, "O", "AUTH") + t.NotNil(external) + u, err := external.Users().Add("service", external.Subject()) + t.NoError(err) + + curve, err := authb.KeyFor(nkeys.PrefixByteCurve) + t.NoError(err) + + users, accounts, key := external.ExternalAuthorization() + t.Empty(users) + t.Empty(accounts) + t.Empty(key) + + t.NoError(external.SetExternalAuthorizationUser([]authb.User{u}, []authb.Account{a}, curve.Public)) + + t.NoError(auth.Commit()) + t.NoError(auth.Reload()) + + external = t.GetAccount(auth, "O", "AUTH") + t.NotNil(external) + + users, accounts, key = external.ExternalAuthorization() + t.Equal(users, []string{u.Subject()}) + t.Equal(accounts, []string{a.Subject()}) + t.Equal(key, curve.Public) + + t.NoError(external.SetExternalAuthorizationUser(nil, nil, "")) + users, accounts, key = external.ExternalAuthorization() + t.Nil(users) + t.Nil(accounts) + t.Empty(key) + + t.NoError(auth.Commit()) + t.NoError(auth.Reload()) + + external = t.GetAccount(auth, "O", "AUTH") + t.NotNil(external) + users, accounts, key = external.ExternalAuthorization() + t.Nil(users) + t.Nil(accounts) + t.Empty(key) +} diff --git a/types.go b/types.go index 57720fe..9a5ff58 100644 --- a/types.go +++ b/types.go @@ -322,6 +322,14 @@ type Account interface { SetTracingContext(opts *TracingContext) error // Tags returns an object that you can use to manage tags for the account Tags() Tags + + // SetExternalAuthorizationUser updates external authorization by associating users public keys, account public keys, and an encryption key. + // ExternalAuthorization requires at the very list one user + SetExternalAuthorizationUser(users []User, accounts []Account, encryption string) error + + // ExternalAuthorization retrieves a list of authorized users, associated accounts, and encryption key. + // if the users value is nil, ExternalAuthorization is not enabled + ExternalAuthorization() ([]string, []string, string) } // Users is an interface for managing users