github.com/kbehouse/nsc@v0.0.6/cmd/addaccount_test.go (about) 1 /* 2 * Copyright 2018-2020 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 "io/ioutil" 21 "path/filepath" 22 "testing" 23 24 "github.com/kbehouse/nsc/cmd/store" 25 "github.com/nats-io/jwt/v2" 26 "github.com/nats-io/nkeys" 27 "github.com/stretchr/testify/require" 28 ) 29 30 func Test_AddAccount(t *testing.T) { 31 ts := NewTestStore(t, "add_account") 32 defer ts.Done(t) 33 34 _, bar, _ := CreateAccountKey(t) 35 // a cluster key 36 ckp, err := nkeys.CreateCluster() 37 require.NoError(t, err) 38 cpk, err := ckp.PublicKey() 39 require.NoError(t, err) 40 41 tests := CmdTests{ 42 {CreateAddAccountCmd(), []string{"add", "account"}, nil, []string{"account name is required"}, true}, 43 {CreateAddAccountCmd(), []string{"add", "account", "--name", "A"}, nil, []string{"generated and stored account key", "added account"}, false}, 44 {CreateAddAccountCmd(), []string{"add", "account", "--name", "A"}, nil, []string{"the account \"A\" already exists"}, true}, 45 {CreateAddAccountCmd(), []string{"add", "account", "--name", "B", "--public-key", bar}, nil, nil, false}, 46 {CreateAddAccountCmd(), []string{"add", "account", "--name", "*"}, nil, []string{"generated and stored account key", "added account"}, false}, 47 {CreateAddAccountCmd(), []string{"add", "account", "--name", "*"}, nil, []string{"generated and stored account key", "added account"}, false}, // should make a new name 48 {CreateAddAccountCmd(), []string{"add", "account", "--name", "X", "--public-key", cpk}, nil, []string{"specified key is not a valid account nkey"}, true}, 49 {CreateAddAccountCmd(), []string{"add", "account", "--name", "badexp", "--expiry", "30d"}, nil, nil, false}, 50 } 51 52 tests.Run(t, "root", "add") 53 } 54 55 func Test_AddAccountNoStore(t *testing.T) { 56 // reset the store 57 require.NoError(t, ForceStoreRoot(t, "")) 58 _, _, err := ExecuteCmd(CreateAddAccountCmd()) 59 require.NotNil(t, err) 60 require.Equal(t, "no stores available", err.Error()) 61 } 62 63 func Test_AddAccountValidateOutput(t *testing.T) { 64 ts := NewTestStore(t, "test") 65 defer ts.Done(t) 66 67 _, _, err := ExecuteCmd(CreateAddAccountCmd(), "--name", "A", "--start", "2018-01-01", "--expiry", "2050-01-01") 68 require.NoError(t, err) 69 validateAddAccountClaims(t, ts) 70 } 71 72 func Test_AddAccountInteractive(t *testing.T) { 73 ts := NewTestStore(t, "test") 74 defer ts.Done(t) 75 76 inputs := []interface{}{"A", true, "2018-01-01", "2050-01-01", 0} 77 78 cmd := CreateAddAccountCmd() 79 HoistRootFlags(cmd) 80 _, _, err := ExecuteInteractiveCmd(cmd, inputs) 81 require.NoError(t, err) 82 validateAddAccountClaims(t, ts) 83 } 84 85 func validateAddAccountClaims(t *testing.T, ts *TestStore) { 86 ac, err := ts.Store.ReadAccountClaim("A") 87 require.NoError(t, err) 88 89 kp, err := ts.KeyStore.GetKeyPair(ac.Subject) 90 require.NoError(t, err) 91 _, err = kp.Seed() 92 require.NoError(t, err, "stored key should be a seed") 93 94 pub, err := kp.PublicKey() 95 require.NoError(t, err) 96 require.Equal(t, ac.Subject, pub, "public key is subject") 97 98 okp, err := ts.KeyStore.GetKeyPair(ac.Issuer) 99 require.NoError(t, err) 100 // operator stores will not return a keypair 101 if okp == nil { 102 okp = kp 103 } 104 105 oppub, err := okp.PublicKey() 106 require.NoError(t, err, "getting public key for operator") 107 require.Equal(t, ac.Issuer, oppub, "operator signed it") 108 109 start, err := ParseExpiry("2018-01-01") 110 require.NoError(t, err) 111 require.Equal(t, start, ac.NotBefore) 112 113 expire, err := ParseExpiry("2050-01-01") 114 require.NoError(t, err) 115 require.Equal(t, expire, ac.Expires) 116 } 117 118 func Test_AddAccountManagedStore(t *testing.T) { 119 as, m := RunTestAccountServer(t) 120 defer as.Close() 121 122 ts := NewTestStoreWithOperatorJWT(t, string(m["operator"])) 123 defer ts.Done(t) 124 125 _, _, err := ExecuteCmd(CreateAddAccountCmd(), "--name", "A", "--start", "2018-01-01", "--expiry", "2050-01-01") 126 require.NoError(t, err) 127 } 128 129 func Test_AddAccountManagedStoreWithSigningKey(t *testing.T) { 130 ts := NewEmptyStore(t) 131 defer ts.Done(t) 132 _, pub, kp := CreateOperatorKey(t) 133 oc := jwt.NewOperatorClaims(pub) 134 oc.Name = "O" 135 s1, psk, sk := CreateOperatorKey(t) 136 ts.KeyStore.Store(sk) 137 oc.SigningKeys.Add(psk) 138 token, err := oc.Encode(kp) 139 require.NoError(t, err) 140 tf := filepath.Join(ts.Dir, "O.jwt") 141 err = Write(tf, []byte(token)) 142 require.NoError(t, err) 143 _, _, err = ExecuteCmd(CreateAddOperatorCmd(), "--url", tf) 144 require.NoError(t, err) 145 // sign with the signing key 146 inputs := []interface{}{"A", true, "0", "0", 0, string(s1)} 147 _, _, err = ExecuteInteractiveCmd(HoistRootFlags(CreateAddAccountCmd()), inputs) 148 require.NoError(t, err) 149 accJWT, err := ioutil.ReadFile(filepath.Join(ts.Dir, "store", "O", "accounts", "A", "A.jwt")) 150 require.NoError(t, err) 151 ac, err := jwt.DecodeAccountClaims(string(accJWT)) 152 require.NoError(t, err) 153 require.False(t, ac.IsSelfSigned()) 154 require.Equal(t, ac.Issuer, psk) 155 require.True(t, oc.DidSign(ac)) 156 // sign with the account key 157 inputs = []interface{}{"B", true, "0", "0", 1, string(s1)} 158 _, _, err = ExecuteInteractiveCmd(HoistRootFlags(CreateAddAccountCmd()), inputs) 159 require.NoError(t, err) 160 accJWT, err = ioutil.ReadFile(filepath.Join(ts.Dir, "store", "O", "accounts", "B", "B.jwt")) 161 require.NoError(t, err) 162 ac, err = jwt.DecodeAccountClaims(string(accJWT)) 163 require.NoError(t, err) 164 require.True(t, ac.IsSelfSigned()) 165 require.False(t, oc.DidSign(ac)) 166 } 167 168 func Test_AddAccountInteractiveSigningKey(t *testing.T) { 169 ts := NewTestStore(t, "O") 170 defer ts.Done(t) 171 172 s1, pk1, _ := CreateOperatorKey(t) 173 _, _, err := ExecuteCmd(CreateEditOperatorCmd(), "--sk", pk1) 174 require.NoError(t, err) 175 176 // sign with the custom key 177 inputs := []interface{}{"A", true, "0", "0", 1, string(s1)} 178 _, _, err = ExecuteInteractiveCmd(HoistRootFlags(CreateAddAccountCmd()), inputs) 179 require.NoError(t, err) 180 181 d, err := ts.Store.Read(store.JwtName("O")) 182 require.NoError(t, err) 183 oc, err := jwt.DecodeOperatorClaims(string(d)) 184 require.NoError(t, err) 185 186 ac, err := ts.Store.ReadAccountClaim("A") 187 require.NoError(t, err) 188 require.Equal(t, ac.Issuer, pk1) 189 require.True(t, oc.DidSign(ac)) 190 require.Equal(t, pk1, ac.Issuer) 191 } 192 193 func Test_AddAccountNameArg(t *testing.T) { 194 ts := NewTestStore(t, "O") 195 defer ts.Done(t) 196 197 _, _, err := ExecuteCmd(HoistRootFlags(CreateAddAccountCmd()), "A") 198 require.NoError(t, err) 199 200 _, err = ts.Store.ReadAccountClaim("A") 201 require.NoError(t, err) 202 } 203 204 func Test_AddAccountWithExistingKey(t *testing.T) { 205 ts := NewTestStore(t, "O") 206 defer ts.Done(t) 207 208 kp, err := nkeys.CreateAccount() 209 require.NoError(t, err) 210 _, err = ts.KeyStore.Store(kp) 211 require.NoError(t, err) 212 pk, err := kp.PublicKey() 213 require.NoError(t, err) 214 215 _, _, err = ExecuteCmd(CreateAddAccountCmd(), "A", "--public-key", pk) 216 require.NoError(t, err) 217 } 218 219 func Test_AddManagedAccountWithExistingKey(t *testing.T) { 220 as, m := RunTestAccountServer(t) 221 defer as.Close() 222 223 ts := NewTestStoreWithOperatorJWT(t, string(m["operator"])) 224 defer ts.Done(t) 225 226 kp, err := nkeys.CreateAccount() 227 require.NoError(t, err) 228 _, err = ts.KeyStore.Store(kp) 229 require.NoError(t, err) 230 pk, err := kp.PublicKey() 231 require.NoError(t, err) 232 233 _, _, err = ExecuteCmd(CreateAddAccountCmd(), "A", "--public-key", pk) 234 require.NoError(t, err) 235 236 // inspect the pushed JWT before it was resigned 237 ac, err := jwt.DecodeAccountClaims(string(m[fmt.Sprintf("SRC_%s", pk)])) 238 require.NoError(t, err) 239 require.Equal(t, pk, ac.Subject) 240 require.Equal(t, pk, ac.Issuer) 241 } 242 243 func Test_AddAccountWithSigningKeyOnly(t *testing.T) { 244 ts := NewTestStore(t, "O") 245 defer ts.Done(t) 246 247 kp, err := nkeys.CreateOperator() 248 require.NoError(t, err) 249 _, err = ts.KeyStore.Store(kp) 250 require.NoError(t, err) 251 pk, err := kp.PublicKey() 252 require.NoError(t, err) 253 require.True(t, ts.KeyStore.HasPrivateKey(pk)) 254 255 _, _, err = ExecuteCmd(CreateEditOperatorCmd(), "--sk", pk) 256 require.NoError(t, err) 257 oc, err := ts.Store.ReadOperatorClaim() 258 require.NoError(t, err) 259 require.NotNil(t, oc) 260 require.NoError(t, ts.KeyStore.Remove(oc.Subject)) 261 require.False(t, ts.KeyStore.HasPrivateKey(oc.Subject)) 262 263 _, _, err = ExecuteCmd(CreateAddAccountCmd(), "--name", "A") 264 require.NoError(t, err) 265 266 _, err = ts.Store.ReadAccountClaim("A") 267 require.NoError(t, err) 268 } 269 270 func Test_AddAccount_Pubs(t *testing.T) { 271 ts := NewTestStore(t, "edit user") 272 defer ts.Done(t) 273 274 _, _, err := ExecuteCmd(CreateAddAccountCmd(), "-n", "A", "--allow-pub", "a,b", "--allow-pubsub", "c", "--deny-pub", "foo", "--deny-pubsub", "bar") 275 require.NoError(t, err) 276 277 cc, err := ts.Store.ReadAccountClaim("A") 278 require.NoError(t, err) 279 require.NotNil(t, cc) 280 require.ElementsMatch(t, cc.DefaultPermissions.Pub.Allow, []string{"a", "b", "c"}) 281 require.ElementsMatch(t, cc.DefaultPermissions.Sub.Allow, []string{"c"}) 282 require.ElementsMatch(t, cc.DefaultPermissions.Pub.Deny, []string{"foo", "bar"}) 283 require.ElementsMatch(t, cc.DefaultPermissions.Sub.Deny, []string{"bar"}) 284 }