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

     1  /*
     2   *
     3   *  * Copyright 2018-2019 The NATS Authors
     4   *  * Licensed under the Apache License, Version 2.0 (the "License");
     5   *  * you may not use this file except in compliance with the License.
     6   *  * You may obtain a copy of the License at
     7   *  *
     8   *  * http://www.apache.org/licenses/LICENSE-2.0
     9   *  *
    10   *  * Unless required by applicable law or agreed to in writing, software
    11   *  * distributed under the License is distributed on an "AS IS" BASIS,
    12   *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *  * See the License for the specific language governing permissions and
    14   *  * limitations under the License.
    15   *
    16   */
    17  
    18  package store
    19  
    20  import (
    21  	"fmt"
    22  	"os"
    23  	"path/filepath"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/nats-io/jwt/v2"
    28  	"github.com/nats-io/nkeys"
    29  	"github.com/stretchr/testify/require"
    30  )
    31  
    32  func MakeTempStore(t *testing.T, name string, kp nkeys.KeyPair) *Store {
    33  	p := MakeTempDir(t)
    34  
    35  	var nk *NamedKey
    36  	if kp != nil {
    37  		nk = &NamedKey{Name: name, KP: kp}
    38  	}
    39  
    40  	s, err := CreateStore(name, p, nk)
    41  	require.NoError(t, err)
    42  	require.NotNil(t, s)
    43  	return s
    44  }
    45  
    46  func MakeTempDir(t *testing.T) string {
    47  	p, err := os.MkdirTemp("", "store_test")
    48  	require.NoError(t, err)
    49  	return p
    50  }
    51  
    52  func CreateTestStoreForOperator(t *testing.T, name string, operator nkeys.KeyPair) *Store {
    53  	s := MakeTempStore(t, name, operator)
    54  
    55  	require.NotNil(t, s)
    56  	require.FileExists(t, filepath.Join(s.Dir, ".nsc"))
    57  	require.True(t, s.Has("", ".nsc"))
    58  
    59  	if operator != nil {
    60  		tokenName := fmt.Sprintf("%s.jwt", SafeName(name))
    61  		require.FileExists(t, filepath.Join(s.Dir, tokenName))
    62  		require.True(t, s.Has("", tokenName))
    63  	}
    64  
    65  	for _, d := range standardDirs {
    66  		require.DirExists(t, filepath.Join(s.Dir, d))
    67  		require.True(t, s.Has(d, ""))
    68  	}
    69  	return s
    70  }
    71  
    72  func CreateTestStore(t *testing.T, name string) *Store {
    73  	var kp nkeys.KeyPair
    74  	_, _, kp = CreateOperatorKey(t)
    75  	return CreateTestStoreForOperator(t, name, kp)
    76  }
    77  
    78  func TestCreateStoreFailsOnNonEmptyDir(t *testing.T) {
    79  	p := MakeTempDir(t)
    80  	fp := filepath.Join(p, "test")
    81  	require.NoError(t, os.WriteFile(fp, []byte("hello"), 0666))
    82  
    83  	_, _, kp := CreateAccountKey(t)
    84  	_, err := CreateStore("foo", p, &NamedKey{Name: "foo", KP: kp})
    85  	require.Error(t, err)
    86  }
    87  
    88  func TestUnsupportedKeyType(t *testing.T) {
    89  	p := MakeTempDir(t)
    90  	fp := filepath.Join(p, "test")
    91  	require.NoError(t, os.WriteFile(fp, []byte("hello"), 0666))
    92  
    93  	kp, err := nkeys.CreateServer()
    94  	require.NoError(t, err)
    95  
    96  	_, err = CreateStore("foo", p, &NamedKey{Name: "foo", KP: kp})
    97  	require.Error(t, err)
    98  }
    99  
   100  func TestOperatorLoadStore(t *testing.T) {
   101  	s := CreateTestStore(t, "test-account")
   102  	ss, err := LoadStore(s.Dir)
   103  	require.NoError(t, err)
   104  	require.NotNil(t, ss)
   105  	require.Equal(t, s.Dir, ss.Dir)
   106  }
   107  
   108  func TestCreateOperatorStore(t *testing.T) {
   109  	CreateTestStore(t, "test-operator")
   110  }
   111  
   112  func TestWriteFile(t *testing.T) {
   113  	s := CreateTestStore(t, "test-account")
   114  	err := s.Write([]byte("foo"), Users, "foo")
   115  	require.NoError(t, err)
   116  
   117  	fp := filepath.Join(s.Dir, Users, "foo")
   118  	require.FileExists(t, fp)
   119  }
   120  
   121  func TestReadFile(t *testing.T) {
   122  	s := CreateTestStore(t, "test-account")
   123  	err := s.Write([]byte("foo"), Users, "foo")
   124  	require.NoError(t, err)
   125  
   126  	fp := filepath.Join(s.Dir, Users, "foo")
   127  	require.FileExists(t, fp)
   128  
   129  	d, err := s.Read(Users, "foo")
   130  	require.NoError(t, err)
   131  	require.Equal(t, "foo", string(d))
   132  }
   133  
   134  func TestListFiles(t *testing.T) {
   135  	s := CreateTestStore(t, "test-account")
   136  	err := s.Write([]byte("foo"), Users, "foo")
   137  	require.NoError(t, err)
   138  
   139  	err = s.Write([]byte("bar"), Users, "bar")
   140  	require.NoError(t, err)
   141  
   142  	infos, err := s.List(Users, "")
   143  	require.NoError(t, err)
   144  
   145  	var names []string
   146  	for _, i := range infos {
   147  		names = append(names, i.Name())
   148  	}
   149  	require.ElementsMatch(t, names, []string{"foo", "bar"})
   150  }
   151  
   152  func TestDeleteFile(t *testing.T) {
   153  	s := CreateTestStore(t, "test-account")
   154  	err := s.Write([]byte("foo"), Users, "foo")
   155  	require.NoError(t, err)
   156  
   157  	fp := filepath.Join(s.Dir, Users, "foo")
   158  	require.FileExists(t, fp)
   159  
   160  	err = s.Delete(Users, "foo")
   161  	require.NoError(t, err)
   162  	require.False(t, s.Has(Users, "foo"))
   163  }
   164  
   165  func TestLoadOperator(t *testing.T) {
   166  	s := CreateTestStore(t, "x")
   167  	require.True(t, s.Has(JwtName("x")))
   168  	c, err := s.LoadRootClaim()
   169  	require.NoError(t, err)
   170  	require.NotNil(t, c)
   171  }
   172  
   173  func TestStoreOperator(t *testing.T) {
   174  	_, _, kp := CreateOperatorKey(t)
   175  	s := CreateTestStoreForOperator(t, "x", kp)
   176  	c, err := s.LoadClaim("x.jwt")
   177  	require.NoError(t, err)
   178  	require.NotNil(t, c)
   179  	exp := time.Now().Unix() + 5
   180  	require.Zero(t, c.Expires)
   181  
   182  	c.Expires = exp
   183  	token, err := c.Encode(kp)
   184  	require.NoError(t, err)
   185  
   186  	_, err = s.StoreClaim([]byte(token))
   187  	require.NoError(t, err)
   188  	c, err = s.LoadClaim("x.jwt")
   189  	require.NoError(t, err)
   190  	require.Equal(t, c.Expires, exp)
   191  }
   192  
   193  func TestStoreAccount(t *testing.T) {
   194  	_, _, kp := CreateOperatorKey(t)
   195  	_, apub, _ := CreateAccountKey(t)
   196  	s := CreateTestStoreForOperator(t, "x", kp)
   197  
   198  	c := jwt.NewAccountClaims(apub)
   199  	c.Name = "foo"
   200  	cd, err := c.Encode(kp)
   201  	require.NoError(t, err)
   202  	_, err = s.StoreClaim([]byte(cd))
   203  	require.NoError(t, err)
   204  
   205  	gc, err := s.LoadClaim(Accounts, "foo", "foo.jwt")
   206  	require.NoError(t, err)
   207  	require.NotNil(t, gc)
   208  	require.Equal(t, gc.Name, "foo")
   209  }
   210  
   211  func TestStoreAccountWithSigningKey(t *testing.T) {
   212  	_, _, kp := CreateOperatorKey(t)
   213  	_, apub, _ := CreateAccountKey(t)
   214  	s := CreateTestStoreForOperator(t, "x", kp)
   215  	oc, err := s.ReadOperatorClaim()
   216  	require.NoError(t, err)
   217  
   218  	_, spk1, skp1 := CreateOperatorKey(t)
   219  	_, spk2, _ := CreateOperatorKey(t)
   220  	oc.SigningKeys.Add(spk1, spk2)
   221  	cd, err := oc.Encode(kp)
   222  	require.NoError(t, err)
   223  	_, err = s.StoreClaim([]byte(cd))
   224  	require.NoError(t, err)
   225  
   226  	oc, err = s.ReadOperatorClaim()
   227  	require.NoError(t, err)
   228  	require.Contains(t, oc.SigningKeys, spk1)
   229  	require.Contains(t, oc.SigningKeys, spk2)
   230  
   231  	c := jwt.NewAccountClaims(apub)
   232  	c.Name = "foo"
   233  	cd, err = c.Encode(skp1)
   234  	require.NoError(t, err)
   235  	_, err = s.StoreClaim([]byte(cd))
   236  	require.NoError(t, err)
   237  
   238  	gc, err := s.LoadClaim(Accounts, "foo", "foo.jwt")
   239  	require.NoError(t, err)
   240  	require.NotNil(t, gc)
   241  	require.Equal(t, gc.Name, "foo")
   242  	require.True(t, oc.DidSign(gc))
   243  }
   244  
   245  func TestStoreUser(t *testing.T) {
   246  	_, _, kp := CreateOperatorKey(t)
   247  	_, apub, akp := CreateAccountKey(t)
   248  	_, upub, _ := CreateUserKey(t)
   249  
   250  	s := CreateTestStoreForOperator(t, "x", kp)
   251  
   252  	ac := jwt.NewAccountClaims(apub)
   253  	ac.Name = "foo"
   254  	cd, err := ac.Encode(kp)
   255  	require.NoError(t, err)
   256  	_, err = s.StoreClaim([]byte(cd))
   257  	require.NoError(t, err)
   258  
   259  	uc := jwt.NewUserClaims(upub)
   260  	uc.Name = "bar"
   261  	ud, err := uc.Encode(akp)
   262  	require.NoError(t, err)
   263  
   264  	_, err = s.StoreClaim([]byte(ud))
   265  	require.NoError(t, err)
   266  
   267  	gc, err := s.LoadClaim(Accounts, "foo", Users, "bar.jwt")
   268  	require.NoError(t, err)
   269  	require.NotNil(t, gc)
   270  	require.Equal(t, gc.Name, "bar")
   271  }
   272  
   273  func TestStoreUserWithSigningKeys(t *testing.T) {
   274  	_, _, kp := CreateOperatorKey(t)
   275  	_, apub, _ := CreateAccountKey(t)
   276  	_, spub, sakp := CreateAccountKey(t)
   277  	_, upub, _ := CreateUserKey(t)
   278  
   279  	s := CreateTestStoreForOperator(t, "x", kp)
   280  
   281  	ac := jwt.NewAccountClaims(apub)
   282  	ac.Name = "foo"
   283  	ac.SigningKeys.Add(spub)
   284  	cd, err := ac.Encode(kp)
   285  	require.NoError(t, err)
   286  	_, err = s.StoreClaim([]byte(cd))
   287  	require.NoError(t, err)
   288  
   289  	uc := jwt.NewUserClaims(upub)
   290  	uc.Name = "bar"
   291  	uc.IssuerAccount = apub
   292  	ud, err := uc.Encode(sakp)
   293  	require.NoError(t, err)
   294  	_, err = s.StoreClaim([]byte(ud))
   295  	require.NoError(t, err)
   296  
   297  	gc, err := s.LoadClaim(Accounts, "foo", Users, "bar.jwt")
   298  	require.NoError(t, err)
   299  	require.NotNil(t, gc)
   300  	require.Equal(t, gc.Name, "bar")
   301  	require.True(t, ac.DidSign(uc))
   302  }
   303  
   304  func TestStore_ListSubContainers(t *testing.T) {
   305  	_, _, kp := CreateOperatorKey(t)
   306  	_, apub, akp := CreateAccountKey(t)
   307  	_, upub, _ := CreateUserKey(t)
   308  
   309  	s := CreateTestStoreForOperator(t, "store", kp)
   310  
   311  	ac := jwt.NewAccountClaims(apub)
   312  	ac.Name = "foo"
   313  	cd, err := ac.Encode(kp)
   314  	require.NoError(t, err)
   315  	rs, err := s.StoreClaim([]byte(cd))
   316  	require.NoError(t, err)
   317  	require.Nil(t, rs)
   318  
   319  	uc := jwt.NewUserClaims(upub)
   320  	uc.Name = "bar"
   321  	ud, err := uc.Encode(akp)
   322  	require.NoError(t, err)
   323  
   324  	_, err = s.StoreClaim([]byte(ud))
   325  	require.NoError(t, err)
   326  
   327  	v, err := s.ListEntries(Accounts, "foo", Users)
   328  	require.NoError(t, err)
   329  	require.NotNil(t, v)
   330  	require.Len(t, v, 1)
   331  	require.Equal(t, "bar", v[0])
   332  }
   333  
   334  func TestStore_GetAccountKeys(t *testing.T) {
   335  	_, _, kp := CreateOperatorKey(t)
   336  	_, apub, _ := CreateAccountKey(t)
   337  
   338  	s := CreateTestStoreForOperator(t, "O", kp)
   339  
   340  	ctx, err := s.GetContext()
   341  	require.NoError(t, err)
   342  
   343  	keys, err := ctx.GetAccountKeys("A")
   344  	require.NoError(t, err)
   345  	require.Nil(t, keys)
   346  
   347  	ac := jwt.NewAccountClaims(apub)
   348  	ac.Name = "A"
   349  	cd, err := ac.Encode(kp)
   350  	require.NoError(t, err)
   351  	rs, err := s.StoreClaim([]byte(cd))
   352  	require.NoError(t, err)
   353  	require.Nil(t, rs)
   354  
   355  	keys, err = ctx.GetAccountKeys("A")
   356  	require.NoError(t, err)
   357  	require.Len(t, keys, 1)
   358  	require.Contains(t, keys, apub)
   359  
   360  	_, apub2, _ := CreateAccountKey(t)
   361  	ac.SigningKeys.Add(apub2)
   362  	cd, err = ac.Encode(kp)
   363  	require.NoError(t, err)
   364  	rs, err = s.StoreClaim([]byte(cd))
   365  	require.NoError(t, err)
   366  	require.Nil(t, rs)
   367  
   368  	keys, err = ctx.GetAccountKeys("A")
   369  	require.NoError(t, err)
   370  	require.Len(t, keys, 2)
   371  	require.Equal(t, apub, keys[0])
   372  	require.Equal(t, apub2, keys[1])
   373  }