Skip to content

Commit

Permalink
[FEAT] account resolver configurations with protocol wss/ws are now a…
Browse files Browse the repository at this point in the history
…ccepted (#619)

* [FEAT] account resolver configurations with protocol wss/ws are now accepted
* [BUMP] bump dependencies
  • Loading branch information
aricart authored Nov 1, 2023
1 parent 1ab6348 commit dc5966c
Show file tree
Hide file tree
Showing 11 changed files with 131 additions and 16 deletions.
8 changes: 8 additions & 0 deletions cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,14 @@ func IsNatsUrl(url string) bool {
return store.IsNatsUrl(url)
}

func IsAccountServerURL(u string) bool {
return store.IsAccountServerURL(u)
}

func IsResolverURL(u string) bool {
return store.IsResolverURL(u)
}

func ValidSigner(kp nkeys.KeyPair, signers []string) (bool, error) {
pk, err := kp.PublicKey()
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions cmd/editoperator.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ func createEditOperatorCmd() *cobra.Command {
cmd.Flags().StringSliceVarP(&params.rmSigningKeys, "rm-sk", "", nil, "remove signing key - comma separated list or option can be specified multiple times")
cmd.Flags().StringSliceVarP(&params.tags, "tag", "", nil, "add tags for user - comma separated list or option can be specified multiple times")
cmd.Flags().StringSliceVarP(&params.rmTags, "rm-tag", "", nil, "remove tag - comma separated list or option can be specified multiple times")
cmd.Flags().StringVarP(&params.asu, "account-jwt-server-url", "u", "", "set account jwt server url for nsc sync (only http/https/nats urls supported if updating with nsc)")
cmd.Flags().StringVarP(&params.asu, "account-jwt-server-url", "u", "", "set account jwt server url for nsc sync (only http/https or nats service (nats/tls/ws/wss) urls supported if updating with nsc)")
cmd.Flags().StringVarP(&params.sysAcc, "system-account", "", "", "set system account by account by public key or name")
cmd.Flags().StringSliceVarP(&params.serviceURLs, "service-url", "n", nil, "add an operator service url for nsc where clients can access the NATS service (only nats/tls urls supported)")
cmd.Flags().StringSliceVarP(&params.rmServiceURLs, "rm-service-url", "", nil, "remove an operator service url for nsc where clients can access the NATS service (only nats/tls urls supported)")
cmd.Flags().StringSliceVarP(&params.serviceURLs, "service-url", "n", nil, "add an operator service url for nsc where clients can access the NATS service (only nats/tls/ws/wss urls supported)")
cmd.Flags().StringSliceVarP(&params.rmServiceURLs, "rm-service-url", "", nil, "remove an operator service url for nsc where clients can access the NATS service (only nats/tls/ws/wss urls supported)")
cmd.Flags().BoolVarP(&params.reqSk, "require-signing-keys", "", false, "require accounts/user to be signed with a signing key")
cmd.Flags().BoolVarP(&params.rmAsu, "rm-account-jwt-server-url", "", false, "clear account server url")
params.TimeParams.BindFlags(cmd)
Expand Down
3 changes: 2 additions & 1 deletion cmd/expirations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ package cmd

import (
"encoding/json"
"github.com/stretchr/testify/require"
"testing"
"time"

"github.com/stretchr/testify/require"
)

func Test_ExpirationsNone(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions cmd/generateactivation.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ func (p *GenerateActivationParams) PostInteractive(ctx ActionCtx) error {
if err != nil {
return err
}
if oc.AccountServerURL != "" && !IsNatsUrl(oc.AccountServerURL) {
if oc.AccountServerURL != "" && IsAccountServerURL(oc.AccountServerURL) {
m := fmt.Sprintf("push the activation to %q", oc.AccountServerURL)
p.push, err = cli.Confirm(m, false)
if err != nil {
Expand Down Expand Up @@ -274,7 +274,7 @@ func (p *GenerateActivationParams) Run(ctx ActionCtx) (store.Status, error) {
}
if oc.AccountServerURL == "" {
return nil, fmt.Errorf("operator %s doesn't have an account server url configured", oc.Name)
} else if IsNatsUrl(oc.AccountServerURL) {
} else if IsResolverURL(oc.AccountServerURL) {
return nil, fmt.Errorf("activation push is only supported for http base account server not nats-resover enabled nats-server")
}
u, err := url.Parse(oc.AccountServerURL)
Expand Down
4 changes: 2 additions & 2 deletions cmd/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (p *PullParams) Validate(ctx ActionCtx) error {
if oc.AccountServerURL == "" {
return fmt.Errorf("operator %q doesn't set account server url - unable to pull", ctx.StoreCtx().Operator.Name)
}
if IsNatsUrl(oc.AccountServerURL) && !p.All {
if IsResolverURL(oc.AccountServerURL) && !p.All {
return fmt.Errorf("operator %q can only pull all jwt - unable to pull by account", ctx.StoreCtx().Operator.Name)
}
return nil
Expand Down Expand Up @@ -253,7 +253,7 @@ func (p *PullParams) Run(ctx ActionCtx) (store.Status, error) {
err := fmt.Errorf("operator has no account server url")
r.AddError("operator %s: %v", op.Name, err)
return r, err
} else if url := op.AccountServerURL; IsNatsUrl(url) {
} else if url := op.AccountServerURL; IsResolverURL(url) {
subR := store.NewReport(store.OK, `pull from cluster using system account`)
r.Add(subR)
ib := nats.NewInbox()
Expand Down
56 changes: 56 additions & 0 deletions cmd/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ func Test_SyncNewerFromNatsResolver(t *testing.T) {
require.NoError(t, err)
dir := ts.AddSubDir(t, "resolver")
data = bytes.ReplaceAll(data, []byte(`dir: './jwt'`), []byte(fmt.Sprintf(`dir: '%s'`, dir)))
t.Log(string(data))
err = os.WriteFile(serverconf, data, 0660)
require.NoError(t, err)
// Create a new account, only known to the nats-server. This account can be pulled
Expand Down Expand Up @@ -190,6 +191,61 @@ func Test_SyncNewerFromNatsResolver(t *testing.T) {
require.Equal(t, claimOrig.ID, claim2.ID)
}

func Test_SyncNewerFromNatsResolverWs(t *testing.T) {
ts := NewEmptyStore(t)
defer ts.Done(t)
_, _, err := ExecuteCmd(createAddOperatorCmd(), "--name", "OP", "--sys")
require.NoError(t, err)
ts.SwitchOperator(t, "OP") // switch the operator so ts is in a usable state to obtain operator key
serverconf := filepath.Join(ts.Dir, "server.conf")
_, _, err = ExecuteCmd(createServerConfigCmd(), "--nats-resolver", "--config-file", serverconf)
require.NoError(t, err)
_, _, err = ExecuteCmd(CreateAddAccountCmd(), "--name", "AC1")
require.NoError(t, err)
// modify the generated file so testing becomes easier by knowing where the jwt directory is
data, err := os.ReadFile(serverconf)
require.NoError(t, err)
dir := ts.AddSubDir(t, "resolver")
ws := `websocket: {
port: -1
no_tls: true
}`
data = append(data, ws...)
data = bytes.ReplaceAll(data, []byte(`dir: './jwt'`), []byte(fmt.Sprintf(`dir: '%s'`, dir)))
err = os.WriteFile(serverconf, data, 0660)
require.NoError(t, err)
// Create a new account, only known to the nats-server. This account can be pulled
opKey, err := ts.Store.GetRootPublicKey()
require.NoError(t, err)
opKp, err := ts.KeyStore.GetKeyPair(opKey)
require.NoError(t, err)
acKp, err := nkeys.CreateAccount()
require.NoError(t, err)
subj, err := acKp.PublicKey()
require.NoError(t, err)
claimOrig := jwt.NewAccountClaims(subj)
claimOrig.Name = "acc-name"
theJwtToPull, err := claimOrig.Encode(opKp)
require.NoError(t, err)
os.WriteFile(dir+string(os.PathSeparator)+subj+".jwt", []byte(theJwtToPull), 0660)
ports := ts.RunServerWithConfig(t, serverconf)
require.NotNil(t, ports)
// only after server start as ports are not yet known in tests
_, _, err = ExecuteCmd(createEditOperatorCmd(), "--account-jwt-server-url", ports.WebSocket[0])
require.NoError(t, err)

_, _, err = ExecuteCmd(createPullCmd(), "--all")
require.NoError(t, err)
// again, this time with system account and user specified
_, _, err = ExecuteCmd(createPullCmd(), "--all", "--system-account", "SYS", "--system-user", "sys")
require.NoError(t, err)
// claim now exists in nsc store
claim2, err := ts.Store.ReadAccountClaim("acc-name")
require.NoError(t, err)
require.NotEmpty(t, claimOrig.ID)
require.Equal(t, claimOrig.ID, claim2.ID)
}

func Test_V2OperatorDoesntFail(t *testing.T) {
_, _, okp := CreateOperatorKey(t)
as, m := RunTestAccountServerWithOperatorKP(t, okp, TasOpts{Vers: 2, OperatorOnlyIfV2: true})
Expand Down
8 changes: 4 additions & 4 deletions cmd/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ func (p *PushCmdParams) validURL(s string) error {
return err
}
scheme := strings.ToLower(u.Scheme)
supported := []string{"http", "https", "nats"}
supported := []string{"http", "https", "nats", "ws", "wss"}

ok := false
for _, v := range supported {
Expand All @@ -271,7 +271,7 @@ func (p *PushCmdParams) PreInteractive(ctx ActionCtx) error {
if p.ASU, err = cli.Prompt("Account Server URL or nats-resolver enabled nats-server URL", p.ASU, cli.Val(p.validURL)); err != nil {
return err
}
if IsNatsUrl(p.ASU) {
if IsResolverURL(p.ASU) {
if p.sysAcc == "" {
if p.sysAcc, err = ctx.StoreCtx().PickAccount(p.sysAcc); err != nil {
return err
Expand Down Expand Up @@ -307,7 +307,7 @@ func (p *PushCmdParams) Validate(ctx ActionCtx) error {
if p.ASU == "" {
return errors.New("no account server url or nats-server url was provided by the operator jwt")
}
if !IsNatsUrl(p.ASU) && p.prune {
if !IsResolverURL(p.ASU) && p.prune {
return errors.New("prune only works for nats based account resolver")
}

Expand Down Expand Up @@ -529,7 +529,7 @@ func (p *PushCmdParams) Run(ctx ActionCtx) (store.Status, error) {
return nil, err
}
r := store.NewDetailedReport(true)
if !IsNatsUrl(p.ASU) {
if !IsResolverURL(p.ASU) {
for _, v := range p.targeted {
sub := store.NewReport(store.OK, "push %s to account server", v)
sub.Opt = store.DetailsOnErrorOrWarning
Expand Down
37 changes: 37 additions & 0 deletions cmd/push_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,40 @@ func Test_SyncBadUrl(t *testing.T) {
require.NoError(t, err)
require.Equal(t, len(filesPre), 2)
}

func Test_SyncWs(t *testing.T) {
ts := NewEmptyStore(t)
defer ts.Done(t)
_, _, err := ExecuteCmd(createAddOperatorCmd(), "--name", "OP", "--sys")
require.NoError(t, err)
serverconf := filepath.Join(ts.Dir, "server.conf")
_, _, err = ExecuteCmd(createServerConfigCmd(), "--nats-resolver", "--config-file", serverconf)
require.NoError(t, err)
_, _, err = ExecuteCmd(CreateAddAccountCmd(), "--name", "AC1")
require.NoError(t, err)
// modify the generated file so testing becomes easier by knowing where the jwt directory is
data, err := os.ReadFile(serverconf)
require.NoError(t, err)
dir := ts.AddSubDir(t, "resolver")

ws := `websocket: {
port: -1
no_tls: true
}`
data = append(data, ws...)
data = bytes.ReplaceAll(data, []byte(`dir: './jwt'`), []byte(fmt.Sprintf(`dir: '%s'`, dir)))
err = os.WriteFile(serverconf, data, 0660)
require.NoError(t, err)
ports := ts.RunServerWithConfig(t, serverconf)
require.NotNil(t, ports)
_, _, err = ExecuteCmd(createEditOperatorCmd(), "--account-jwt-server-url", ports.WebSocket[0])
require.NoError(t, err)
// Try again, thus also testing if the server is still around
// Provide explicit system account user to connect
_, _, err = ExecuteCmd(createPushCmd(), "--all", "--system-account", "SYS", "--system-user", "sys")
require.NoError(t, err)
// test to assure AC1/AC2/SYS where pushed
filesPre, err := filepath.Glob(dir + string(os.PathSeparator) + "*.jwt")
require.NoError(t, err)
require.Equal(t, len(filesPre), 2)
}
15 changes: 14 additions & 1 deletion cmd/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,19 @@ func IsNatsUrl(url string) bool {
return strings.HasPrefix(url, "nats://") || strings.HasPrefix(url, ",nats://")
}

func IsAccountServerURL(u string) bool {
u = strings.ToLower(u)
return strings.HasPrefix(u, "http://") || strings.HasPrefix(u, "https://")
}

func IsResolverURL(u string) bool {
u = strings.ToLower(u)
return strings.HasPrefix(u, "nats://") ||
strings.HasPrefix(u, "tls://") ||
strings.HasPrefix(u, "ws://") ||
strings.HasPrefix(u, "wss://")
}

func (s *Store) handleManagedAccount(data []byte) (*Report, error) {
ac, err := jwt.DecodeAccountClaims(string(data))
if err != nil {
Expand All @@ -407,7 +420,7 @@ func (s *Store) handleManagedAccount(data []byte) (*Report, error) {
return nil, fmt.Errorf("unable to push to the operator - failed to read operator claim: %w", err)
}
r := NewDetailedReport(false)
if oc.AccountServerURL == "" || IsNatsUrl(oc.AccountServerURL) {
if oc.AccountServerURL == "" || IsResolverURL(oc.AccountServerURL) {
r.Label = "stored self signed account jwt"
r.AddWarning("unable to push to %q - operator doesn't set an account server url or manual exchange necessary", oc.Name)
return r, nil
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/nats-io/cliprompts/v2 v2.0.0-20231014115920-801ca035562a
github.com/nats-io/jsm.go v0.1.0
github.com/nats-io/jwt/v2 v2.5.2
github.com/nats-io/jwt/v2 v2.5.3
github.com/nats-io/nats-server/v2 v2.10.4
github.com/nats-io/nats.go v1.31.0
github.com/nats-io/nkeys v0.4.6
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ github.com/nats-io/cliprompts/v2 v2.0.0-20231014115920-801ca035562a h1:28qvB6peS
github.com/nats-io/cliprompts/v2 v2.0.0-20231014115920-801ca035562a/go.mod h1:oweZn7AeaVJYKlNHfCIhznJVsdySLSng55vfuINE/d0=
github.com/nats-io/jsm.go v0.1.0 h1:H2gYCee/iyBDjUftPOr5fEPWAcG/+fyVl89IWiy6AC4=
github.com/nats-io/jsm.go v0.1.0/go.mod h1:snnYORje42cEDCX5QygzeoVA2KiWVbiIJbLfGIvXW08=
github.com/nats-io/jwt/v2 v2.5.2 h1:DhGH+nKt+wIkDxM6qnVSKjokq5t59AZV5HRcFW0zJwU=
github.com/nats-io/jwt/v2 v2.5.2/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
github.com/nats-io/jwt/v2 v2.5.3 h1:/9SWvzc6hTfamcgXJ3uYRpgj+QuY2aLNqRiqrKcrpEo=
github.com/nats-io/jwt/v2 v2.5.3/go.mod h1:iysuPemFcc7p4IoYots3IuELSI4EDe9Y0bQMe+I3Bf4=
github.com/nats-io/nats-server/v2 v2.10.4 h1:uB9xcwon3tPXWAdmTJqqqC6cie3yuPWHJjjTBgaPNus=
github.com/nats-io/nats-server/v2 v2.10.4/go.mod h1:eWm2JmHP9Lqm2oemB6/XGi0/GwsZwtWf8HIPUsh+9ns=
github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E=
Expand Down

0 comments on commit dc5966c

Please sign in to comment.