github.com/kbehouse/nsc@v0.0.6/cmd/generateprofile_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 "encoding/json" 20 "fmt" 21 "net/url" 22 "path" 23 "testing" 24 25 "github.com/nats-io/jwt/v2" 26 27 "github.com/stretchr/testify/require" 28 ) 29 30 func Test_ParseNscURLs(t *testing.T) { 31 type test struct { 32 u string 33 err bool 34 want *NscURL 35 } 36 37 tests := []test{ 38 {u: "nsc://", err: true, want: nil}, 39 {u: "http://one", err: true, want: nil}, 40 {u: "nsc://one", err: false, want: &NscURL{operator: "one"}}, 41 {u: "nsc://one one/two", err: false, want: &NscURL{operator: "one one", account: "two"}}, 42 {u: "nsc://one/two/three", err: false, want: &NscURL{operator: "one", account: "two", user: "three"}}, 43 {u: "nsc://one?hello&world", err: false, want: &NscURL{operator: "one", qs: "hello&world"}}, 44 } 45 46 for _, tc := range tests { 47 u, err := ParseNscURL(tc.u) 48 if tc.err && err == nil { 49 t.Fatalf("error parsing %q - expected error, but got none", tc.u) 50 } 51 if !tc.err && err != nil { 52 t.Fatalf("error parsing %q - expected no error, but got %v", tc.u, err) 53 } 54 require.Equal(t, tc.want, u) 55 } 56 } 57 58 func Test_ParseNscURLQuery(t *testing.T) { 59 type test struct { 60 u string 61 want map[Arg]string 62 } 63 64 tests := []test{ 65 {u: "nsc://one?seed&name&key", want: map[Arg]string{seed: "", name: "", key: ""}}, 66 {u: "nsc://one/two/three?store=/tmp/storedir&keystore=/tmp/key+dir", 67 want: map[Arg]string{ 68 storeDir: "/tmp/storedir", 69 keystoreDir: "/tmp/key dir"}}, 70 } 71 72 for _, tc := range tests { 73 u, err := ParseNscURL(tc.u) 74 if err != nil { 75 t.Fatalf("failed parsing query %q: %v", tc.u, err) 76 } 77 q, err := u.query() 78 require.NoError(t, err) 79 require.Equal(t, tc.want, q) 80 } 81 } 82 83 func Test_NscURLEncodedNames(t *testing.T) { 84 t.Log(url.QueryEscape("My Company Inc.")) 85 nu, err := ParseNscURL("nsc://My+Company+Inc./Account+Name/") 86 require.NoError(t, err) 87 o, err := nu.getOperator() 88 require.NoError(t, err) 89 require.Equal(t, "My Company Inc.", o) 90 91 a, err := nu.getAccount() 92 require.NoError(t, err) 93 require.Equal(t, "Account Name", a) 94 95 u, err := nu.getUser() 96 require.NoError(t, err) 97 require.Equal(t, "", u) 98 } 99 100 func loadResults(t *testing.T, out string) Profile { 101 d, err := Read(out) 102 require.NoError(t, err) 103 var r Profile 104 require.NoError(t, json.Unmarshal(d, &r)) 105 return r 106 } 107 108 func Test_ProfileIDs(t *testing.T) { 109 ts := NewTestStore(t, "O") 110 defer ts.Done(t) 111 112 ts.AddAccount(t, "A") 113 ts.AddUser(t, "A", "U") 114 115 o := ts.GetOperatorPublicKey(t) 116 a := ts.GetAccountPublicKey(t, "A") 117 u := ts.GetUserPublicKey(t, "A", "U") 118 119 out := path.Join(ts.Dir, "out.json") 120 nu := fmt.Sprintf("nsc://%s/%s/%s?operatorName&accountName&userName", o, a, u) 121 _, _, err := ExecuteCmd(createProfileCmd(), "-o", out, nu) 122 require.NoError(t, err) 123 124 r := loadResults(t, out) 125 require.Equal(t, "O", r.Operator.Name) 126 require.Equal(t, "A", r.Account.Name) 127 require.Equal(t, "U", r.User.Name) 128 } 129 130 func Test_ProfileSeedIDs(t *testing.T) { 131 ts := NewTestStore(t, "O") 132 defer ts.Done(t) 133 134 // add a signing key 135 osk, opk, okp := CreateOperatorKey(t) 136 ts.KeyStore.Store(okp) 137 oc, err := ts.Store.ReadOperatorClaim() 138 require.NoError(t, err) 139 kp, err := ts.KeyStore.GetKeyPair(oc.Issuer) 140 require.NoError(t, err) 141 require.NoError(t, err) 142 oc.SigningKeys.Add(opk) 143 sjwt, err := oc.Encode(kp) 144 require.NoError(t, err) 145 _, err = ts.Store.StoreClaim([]byte(sjwt)) 146 require.NoError(t, err) 147 148 ts.AddAccount(t, "A") 149 ts.AddUser(t, "A", "U") 150 151 o := ts.GetOperatorPublicKey(t) 152 a := ts.GetAccountPublicKey(t, "A") 153 u := ts.GetUserPublicKey(t, "A", "U") 154 155 out := path.Join(ts.Dir, "out.json") 156 nu := fmt.Sprintf("nsc://%s/%s/%s?operatorSeed=%s", o, a, u, opk) 157 _, _, err = ExecuteCmd(createProfileCmd(), "-o", out, nu) 158 require.NoError(t, err) 159 160 r := loadResults(t, out) 161 require.Equal(t, string(osk), r.Operator.Seed) 162 } 163 164 func Test_ProfileStoreAndKeysDir(t *testing.T) { 165 // create store 166 ts := NewTestStore(t, "O") 167 defer ts.Done(t) 168 ts.AddAccount(t, "A") 169 ts.AddUser(t, "A", "U") 170 opk := ts.GetOperatorPublicKey(t) 171 apk := ts.GetAccountPublicKey(t, "A") 172 upk := ts.GetUserPublicKey(t, "A", "U") 173 174 // context for the store is replaced 175 ts2 := NewTestStore(t, "OO") 176 defer ts2.Done(t) 177 ts2.AddAccount(t, "AA") 178 ts2.AddUser(t, "AA", "UU") 179 180 stdout, _, err := ExecuteCmd(rootCmd, "describe", "operator", "--raw") 181 require.NoError(t, err) 182 ojwt, err := jwt.DecodeOperatorClaims(stdout) 183 require.NoError(t, err) 184 require.Equal(t, "OO", ojwt.Name) 185 186 out := path.Join(ts.Dir, "out.json") 187 storeDir := path.Join(ts.Dir, "store") 188 keyDir := path.Join(ts.Dir, "keys") 189 u := fmt.Sprintf("nsc://O/A/U?operatorName&accountName&userName&operatorKey&accountKey&userKey&store=%s&keyStore=%s", storeDir, keyDir) 190 191 _, _, err = ExecuteCmd(rootCmd, "generate", "profile", "-o", out, u) 192 require.NoError(t, err) 193 r := loadResults(t, out) 194 195 require.Equal(t, "O", r.Operator.Name) 196 require.Equal(t, opk, r.Operator.Key) 197 require.Equal(t, "A", r.Account.Name) 198 require.Equal(t, apk, r.Account.Key) 199 require.Equal(t, "U", r.User.Name) 200 require.Equal(t, upk, r.User.Key) 201 } 202 203 func TestKey_ProfileBasics(t *testing.T) { 204 type test struct { 205 u string 206 want []Arg 207 } 208 209 tests := []test{ 210 {u: "nsc://O?operatorSeed&operatorKey", want: []Arg{operatorKey, operatorSeed}}, 211 {u: "nsc://O?key&seed", want: []Arg{operatorKey, operatorSeed}}, 212 {u: "nsc://O/A?key&seed", want: []Arg{accountKey, accountSeed}}, 213 {u: "nsc://O/A/U?key&seed", want: []Arg{userKey, userSeed}}, 214 } 215 216 for _, tc := range tests { 217 // create an env matching the u 218 u, err := ParseNscURL(tc.u) 219 if err != nil { 220 t.Fatalf("error parsing %q", tc.u) 221 } 222 ts := NewTestStore(t, u.operator) 223 require.NoError(t, err) 224 oseed, err := ts.OperatorKey.Seed() 225 require.NoError(t, err) 226 opub, err := ts.OperatorKey.PublicKey() 227 require.NoError(t, err) 228 229 var aseed []byte 230 var apub string 231 if u.account != "" { 232 ts.AddAccount(t, u.account) 233 akp := ts.GetAccountKey(t, u.account) 234 aseed, err = akp.Seed() 235 require.NoError(t, err) 236 apub, err = akp.PublicKey() 237 require.NoError(t, err) 238 } 239 var useed []byte 240 var upub string 241 if u.user != "" { 242 ts.AddUser(t, u.account, u.user) 243 ukp := ts.GetUserKey(t, u.account, u.user) 244 useed, err = ukp.Seed() 245 require.NoError(t, err) 246 upub, err = ukp.PublicKey() 247 require.NoError(t, err) 248 } 249 250 // execute the command 251 out := path.Join(ts.Dir, "out.json") 252 _, _, err = ExecuteCmd(createProfileCmd(), "-o", out, tc.u) 253 require.NoError(t, err) 254 r := loadResults(t, out) 255 256 q, err := u.query() 257 require.NoError(t, err) 258 require.Equal(t, len(tc.want), len(q)) 259 // check ask keys 260 for _, k := range tc.want { 261 switch k { 262 case operatorKey: 263 require.Equal(t, opub, r.Operator.Key) 264 case accountKey: 265 require.Equal(t, apub, r.Account.Key) 266 case userKey: 267 require.Equal(t, upub, r.User.Key) 268 case key: 269 if u.user != "" { 270 require.Equal(t, upub, r.User.Key) 271 } else if u.account != "" { 272 require.Equal(t, apub, r.Account.Key) 273 } else { 274 require.Equal(t, opub, r.Operator.Key) 275 } 276 case operatorSeed: 277 require.Equal(t, string(oseed), r.Operator.Seed) 278 case accountSeed: 279 require.Equal(t, string(aseed), r.Account.Seed) 280 case userSeed: 281 require.Equal(t, string(useed), r.User.Seed) 282 case seed: 283 if u.user != "" { 284 require.Equal(t, string(useed), r.User.Seed) 285 } else if u.account != "" { 286 require.Equal(t, string(aseed), r.Account.Seed) 287 } else { 288 require.Equal(t, string(oseed), r.Operator.Seed) 289 } 290 case storeDir: 291 case keystoreDir: 292 } 293 } 294 295 ts.Done(t) 296 } 297 }