github.com/nats-io/nsc@v0.0.0-20221206222106-35db9400b257/cmd/tools_test.go (about)

     1  /*
     2   * Copyright 2018-2019 The NATS Authors
     3   * Licensed under the Apache License, Version 2.0 (the "License");
     4   * you may not use this file except in compliance with the License.
     5   * You may obtain a copy of the License at
     6   *
     7   * http://www.apache.org/licenses/LICENSE-2.0
     8   *
     9   * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15  
    16  package cmd
    17  
    18  import (
    19  	"fmt"
    20  	"log"
    21  	"path/filepath"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	nats "github.com/nats-io/nats.go"
    27  	"github.com/nats-io/nuid"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  func TestPub(t *testing.T) {
    32  	ts := NewTestStore(t, "O")
    33  	defer ts.Done(t)
    34  	ts.AddAccount(t, "A")
    35  	ts.AddUser(t, "A", "U")
    36  
    37  	// create the basic configuration
    38  	serverconf := filepath.Join(ts.Dir, "server.conf")
    39  	_, _, err := ExecuteCmd(createServerConfigCmd(), "--mem-resolver",
    40  		"--config-file", serverconf)
    41  	require.NoError(t, err)
    42  
    43  	// start a server with the config at a random port
    44  	ports := ts.RunServerWithConfig(t, serverconf)
    45  
    46  	// with the captured ports, regenerate the operator jwt
    47  	// we only need the client to update
    48  	_, _, err = ExecuteCmd(createEditOperatorCmd(),
    49  		"--service-url", strings.Join(ports.Nats, ","))
    50  	require.NoError(t, err)
    51  
    52  	// create a conn to the server
    53  	nc, err := nats.Connect(strings.Join(ports.Nats, ","),
    54  		nats.UserCredentials(ts.KeyStore.CalcUserCredsPath("A", "U")))
    55  	require.NoError(t, err)
    56  	defer nc.Close()
    57  
    58  	// generate a random subject/payload
    59  	v := nuid.Next()
    60  	c := make(chan *nats.Msg)
    61  	_, err = nc.Subscribe(v, func(m *nats.Msg) {
    62  		c <- m
    63  	})
    64  	require.NoError(t, err)
    65  	require.NoError(t, nc.Flush())
    66  
    67  	// pub a message
    68  	_, _, err = ExecuteCmd(createPubCmd(), v, v)
    69  	require.NoError(t, err)
    70  
    71  	control := <-c
    72  	require.NotNil(t, control)
    73  	require.Equal(t, control.Subject, v)
    74  	require.Equal(t, []byte(v), control.Data)
    75  }
    76  
    77  func TestPubPermissionViolation(t *testing.T) {
    78  	ts := NewTestStore(t, "O")
    79  	defer ts.Done(t)
    80  	ts.AddAccount(t, "A")
    81  
    82  	// generate a random subject/payload
    83  	v := nuid.Next()
    84  
    85  	ts.AddUser(t, "A", "U")
    86  	_, _, err := ExecuteCmd(createEditUserCmd(), "--deny-pub", v)
    87  	require.NoError(t, err)
    88  
    89  	// create the basic configuration
    90  	serverconf := filepath.Join(ts.Dir, "server.conf")
    91  	_, _, err = ExecuteCmd(createServerConfigCmd(), "--mem-resolver",
    92  		"--config-file", serverconf)
    93  	require.NoError(t, err)
    94  
    95  	// start a server with the config at a random port
    96  	ports := ts.RunServerWithConfig(t, serverconf)
    97  
    98  	// with the captured ports, regenerate the operator jwt
    99  	// we only need the client to update
   100  	_, _, err = ExecuteCmd(createEditOperatorCmd(),
   101  		"--service-url", strings.Join(ports.Nats, ","))
   102  	require.NoError(t, err)
   103  
   104  	// create a conn to the server
   105  	nc, err := nats.Connect(strings.Join(ports.Nats, ","),
   106  		nats.UserCredentials(ts.KeyStore.CalcUserCredsPath("A", "U")))
   107  	require.NoError(t, err)
   108  	defer nc.Close()
   109  
   110  	// pub a message
   111  	_, _, err = ExecuteCmd(createPubCmd(), v, v)
   112  	require.Error(t, err)
   113  	require.Contains(t, err.Error(), "Permissions Violation")
   114  }
   115  
   116  func TestSub(t *testing.T) {
   117  	ts := NewTestStore(t, "O")
   118  	defer ts.Done(t)
   119  	ts.AddAccount(t, "A")
   120  	ts.AddUser(t, "A", "U")
   121  
   122  	// create the basic configuration
   123  	conf := filepath.Join(ts.Dir, "server.conf")
   124  	_, _, err := ExecuteCmd(createServerConfigCmd(), "--mem-resolver",
   125  		"--config-file", conf)
   126  	require.NoError(t, err)
   127  
   128  	// start a server with the config at a random port
   129  	ports := ts.RunServerWithConfig(t, conf)
   130  
   131  	// with the captured ports, regenerate the operator jwt - we only need the client to update
   132  	_, _, err = ExecuteCmd(createEditOperatorCmd(),
   133  		"--service-url", strings.Join(ports.Nats, ","))
   134  	require.NoError(t, err)
   135  
   136  	// generate a random subject/payload
   137  	v := nuid.Next()
   138  
   139  	log.SetFlags(log.LstdFlags)
   140  	// subscribe a message
   141  	type po struct {
   142  		stdout string
   143  		stderr string
   144  		err    error
   145  	}
   146  	c := make(chan po)
   147  	go func() {
   148  		var r po
   149  		r.stdout, r.stderr, r.err = ExecuteCmd(createSubCmd(), "--max-messages", "1", v)
   150  		c <- r
   151  	}()
   152  
   153  	// wait for client
   154  	ts.WaitForClient(t, "nsc_sub", 1, 60*time.Second)
   155  
   156  	// create a conn to the server
   157  	creds := ts.KeyStore.CalcUserCredsPath("A", "U")
   158  	nc := ts.CreateClient(t, nats.UserCredentials(creds))
   159  	require.NoError(t, nc.Flush())
   160  	err = nc.Publish(v, []byte(v))
   161  	require.NoError(t, err)
   162  	require.NoError(t, nc.Flush())
   163  
   164  	select {
   165  	case r := <-c:
   166  		t.Log(r.stdout)
   167  		t.Log(r.stderr)
   168  		t.Log(r.err)
   169  		require.NoError(t, r.err)
   170  		require.Contains(t, r.stderr, fmt.Sprintf("received on [%s]: '%s'", v, v))
   171  	case <-time.After(25 * time.Second):
   172  		t.Fatal("timed out")
   173  	}
   174  }
   175  
   176  func TestSubPermissionViolation(t *testing.T) {
   177  	ts := NewTestStore(t, "O")
   178  	defer ts.Done(t)
   179  	ts.AddAccount(t, "A")
   180  
   181  	// generate a random subject/payload
   182  	v := nuid.Next()
   183  
   184  	ts.AddUser(t, "A", "U")
   185  	_, _, err := ExecuteCmd(createEditUserCmd(), "--deny-sub", v)
   186  	require.NoError(t, err)
   187  
   188  	// create the basic configuration
   189  	conf := filepath.Join(ts.Dir, "server.conf")
   190  	_, _, err = ExecuteCmd(createServerConfigCmd(), "--mem-resolver",
   191  		"--config-file", conf)
   192  	require.NoError(t, err)
   193  
   194  	// start a server with the config at a random port
   195  	ports := ts.RunServerWithConfig(t, conf)
   196  
   197  	// with the captured ports, regenerate the operator jwt - we only need the client to update
   198  	_, _, err = ExecuteCmd(createEditOperatorCmd(),
   199  		"--service-url", strings.Join(ports.Nats, ","))
   200  	require.NoError(t, err)
   201  
   202  	log.SetFlags(log.LstdFlags)
   203  
   204  	_, _, err = ExecuteCmd(createSubCmd(), "--max-messages", "1", v)
   205  	require.Error(t, err)
   206  	require.Contains(t, err.Error(), "Permissions Violation")
   207  }
   208  
   209  func TestReq(t *testing.T) {
   210  	ts := NewTestStore(t, "O")
   211  	defer ts.Done(t)
   212  	ts.AddAccount(t, "A")
   213  	ts.AddUser(t, "A", "U")
   214  
   215  	// create the basic configuration
   216  	conf := filepath.Join(ts.Dir, "server.conf")
   217  
   218  	_, _, err := ExecuteCmd(createServerConfigCmd(), "--mem-resolver",
   219  		"--config-file", conf)
   220  	require.NoError(t, err)
   221  
   222  	// start a server with the config at a random port
   223  	ports := ts.RunServerWithConfig(t, conf)
   224  
   225  	// with the captured ports, regenerate the operator jwt - we only need the client to update
   226  	_, _, err = ExecuteCmd(createEditOperatorCmd(),
   227  		"--service-url", strings.Join(ports.Nats, ","))
   228  	require.NoError(t, err)
   229  
   230  	// generate a random subject/payload
   231  	v := nuid.Next()
   232  
   233  	// create a conn to the server
   234  	creds := ts.KeyStore.CalcUserCredsPath("A", "U")
   235  	nc := ts.CreateClient(t, nats.UserCredentials(creds))
   236  	require.NoError(t, nc.Flush())
   237  	sub, err := nc.Subscribe(v, func(m *nats.Msg) {
   238  		require.NotEmpty(t, m.Reply)
   239  		// reply with the payload in uppercase
   240  		require.NoError(t, m.Respond([]byte(strings.ToUpper(string(m.Data)))))
   241  	})
   242  	require.NoError(t, err)
   243  	require.NoError(t, sub.AutoUnsubscribe(1))
   244  	require.NoError(t, nc.Flush())
   245  
   246  	_, stderr, err := ExecuteCmd(createToolReqCmd(), v, v)
   247  	require.NoError(t, err)
   248  	require.Contains(t, stderr, strings.ToUpper(v))
   249  }
   250  
   251  func TestReply(t *testing.T) {
   252  	ts := NewTestStore(t, "O")
   253  	defer ts.Done(t)
   254  	ts.AddAccount(t, "A")
   255  	ts.AddUser(t, "A", "U")
   256  
   257  	// create the basic configuration
   258  	conf := filepath.Join(ts.Dir, "server.conf")
   259  	_, _, err := ExecuteCmd(createServerConfigCmd(), "--mem-resolver",
   260  		"--config-file", conf)
   261  	require.NoError(t, err)
   262  
   263  	// start a server with the config at a random port
   264  	ports := ts.RunServerWithConfig(t, conf)
   265  
   266  	// with the captured ports, regenerate the operator jwt - we only need the client to update
   267  	_, _, err = ExecuteCmd(createEditOperatorCmd(),
   268  		"--service-url", strings.Join(ports.Nats, ","))
   269  	require.NoError(t, err)
   270  
   271  	// generate a random subject/payload
   272  	v := nuid.Next()
   273  
   274  	// subscribe a message
   275  	type po struct {
   276  		stdout string
   277  		stderr string
   278  		err    error
   279  	}
   280  	c := make(chan po)
   281  	go func() {
   282  		var r po
   283  		r.stdout, r.stderr, r.err = ExecuteCmd(createReplyCmd(), "--max-messages", "1", v)
   284  		c <- r
   285  	}()
   286  
   287  	// wait for client
   288  	ts.WaitForClient(t, "nsc_reply", 1, 60*time.Second)
   289  
   290  	// create a conn to the server
   291  	creds := ts.KeyStore.CalcUserCredsPath("A", "U")
   292  	nc := ts.CreateClient(t, nats.UserCredentials(creds))
   293  	require.NoError(t, nc.Flush())
   294  
   295  	m, err := nc.Request(v, []byte(v), 15*time.Second)
   296  	require.NoError(t, err)
   297  	require.Equal(t, v, string(m.Data))
   298  }
   299  
   300  func TestReplyPermissionViolation(t *testing.T) {
   301  	ts := NewTestStore(t, "O")
   302  	defer ts.Done(t)
   303  	ts.AddAccount(t, "A")
   304  
   305  	// generate a random subject/payload
   306  	v := nuid.Next()
   307  
   308  	ts.AddUser(t, "A", "U")
   309  	_, _, err := ExecuteCmd(createEditUserCmd(), "--deny-sub", v)
   310  	require.NoError(t, err)
   311  
   312  	// create the basic configuration
   313  	conf := filepath.Join(ts.Dir, "server.conf")
   314  	_, _, err = ExecuteCmd(createServerConfigCmd(), "--mem-resolver",
   315  		"--config-file", conf)
   316  	require.NoError(t, err)
   317  
   318  	// start a server with the config at a random port
   319  	ports := ts.RunServerWithConfig(t, conf)
   320  
   321  	// with the captured ports, regenerate the operator jwt - we only need the client to update
   322  	_, _, err = ExecuteCmd(createEditOperatorCmd(),
   323  		"--service-url", strings.Join(ports.Nats, ","))
   324  	require.NoError(t, err)
   325  
   326  	_, _, err = ExecuteCmd(createReplyCmd(), "--max-messages", "1", v)
   327  	require.Error(t, err)
   328  	require.Contains(t, err.Error(), "Permissions Violation")
   329  }
   330  
   331  func Test_EncryptDecrypt(t *testing.T) {
   332  	ts := NewTestStore(t, "O")
   333  	defer ts.Done(t)
   334  
   335  	k := ts.GetOperatorPublicKey(t)
   336  	text := "this is a test"
   337  	et, err := Encrypt(k, []byte(text))
   338  	require.NoError(t, err)
   339  	od, err := Decrypt(k, et)
   340  	require.NoError(t, err)
   341  	require.Equal(t, text, string(od))
   342  }