github.com/nats-io/nsc/v2@v2.8.7-0.20240307184528-efd7023c6896/cmd/editaccount_test.go (about) 1 /* 2 * Copyright 2018-2024 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 "github.com/nats-io/jwt/v2" 21 "testing" 22 "time" 23 24 "github.com/nats-io/nkeys" 25 "github.com/stretchr/testify/require" 26 ) 27 28 func Test_EditAccount(t *testing.T) { 29 ts := NewTestStore(t, "edit account") 30 defer ts.Done(t) 31 32 ts.AddAccount(t, "A") 33 ts.AddAccount(t, "B") 34 35 tests := CmdTests{ 36 {createEditAccount(), []string{"edit", "account"}, nil, []string{"specify an edit option"}, true}, 37 {createEditAccount(), []string{"edit", "account", "--info-url", "http://foo/bar"}, nil, []string{"changed info url to"}, false}, 38 {createEditAccount(), []string{"edit", "account", "--description", "my account is about this"}, nil, []string{"changed description to"}, false}, 39 {createEditAccount(), []string{"edit", "account", "--tag", "A", "--name", "A"}, nil, []string{"edited account \"A\""}, false}, 40 } 41 42 tests.Run(t, "root", "edit") 43 } 44 45 func Test_EditAccountRequired(t *testing.T) { 46 ts := NewTestStore(t, "edit account") 47 defer ts.Done(t) 48 49 ts.AddAccount(t, "A") 50 ts.AddAccount(t, "B") 51 require.NoError(t, GetConfig().SetAccount("")) 52 _, _, err := ExecuteCmd(createEditAccount(), "--tag", "A") 53 require.Error(t, err) 54 require.Contains(t, "an account is required", err.Error()) 55 } 56 57 func Test_EditAccount_Tag(t *testing.T) { 58 ts := NewTestStore(t, "edit account") 59 defer ts.Done(t) 60 61 ts.AddAccount(t, "A") 62 _, _, err := ExecuteCmd(createEditAccount(), "--tag", "A,B,C") 63 require.NoError(t, err) 64 65 ac, err := ts.Store.ReadAccountClaim("A") 66 require.NoError(t, err) 67 68 require.Len(t, ac.Tags, 3) 69 require.ElementsMatch(t, ac.Tags, []string{"a", "b", "c"}) 70 } 71 72 func Test_EditAccount_RmTag(t *testing.T) { 73 ts := NewTestStore(t, "edit account") 74 defer ts.Done(t) 75 76 ts.AddAccount(t, "A") 77 _, _, err := ExecuteCmd(createEditAccount(), "--tag", "A,B,C") 78 require.NoError(t, err) 79 80 _, _, err = ExecuteCmd(createEditAccount(), "--rm-tag", "A,B") 81 require.NoError(t, err) 82 83 ac, err := ts.Store.ReadAccountClaim("A") 84 require.NoError(t, err) 85 86 require.Len(t, ac.Tags, 1) 87 require.ElementsMatch(t, ac.Tags, []string{"c"}) 88 } 89 90 func Test_EditAccount_Times(t *testing.T) { 91 ts := NewTestStore(t, "edit account") 92 defer ts.Done(t) 93 94 ts.AddAccount(t, "A") 95 96 _, _, err := ExecuteCmd(createEditAccount(), "--start", "2018-01-01", "--expiry", "2050-01-01") 97 require.NoError(t, err) 98 99 start, err := ParseExpiry("2018-01-01") 100 require.NoError(t, err) 101 102 expiry, err := ParseExpiry("2050-01-01") 103 require.NoError(t, err) 104 105 ac, err := ts.Store.ReadAccountClaim("A") 106 require.NoError(t, err) 107 require.Equal(t, start, ac.NotBefore) 108 require.Equal(t, expiry, ac.Expires) 109 } 110 111 func Test_EditAccountLimits(t *testing.T) { 112 ts := NewTestStore(t, "edit account") 113 defer ts.Done(t) 114 115 ts.AddAccount(t, "A") 116 _, _, err := ExecuteCmd(createEditAccount(), "--conns", "5", "--data", "10mib", "--exports", "15", 117 "--imports", "20", "--payload", "1Kib", "--subscriptions", "30", "--leaf-conns", "31", 118 "--js-streams", "5", "--js-consumer", "6", "--js-disk-storage", "7", "--js-mem-storage", "8", 119 "--js-max-disk-stream", "9mib", "--js-max-mem-stream", "10", "--js-max-ack-pending", "11", "--js-max-bytes-required") 120 require.NoError(t, err) 121 122 ac, err := ts.Store.ReadAccountClaim("A") 123 require.NoError(t, err) 124 require.Equal(t, int64(5), ac.Limits.Conn) 125 require.Equal(t, int64(31), ac.Limits.LeafNodeConn) 126 require.Equal(t, int64(1024*1024*10), ac.Limits.Data) 127 require.Equal(t, int64(15), ac.Limits.Exports) 128 require.Equal(t, int64(20), ac.Limits.Imports) 129 require.Equal(t, int64(1024), ac.Limits.Payload) 130 require.Equal(t, int64(30), ac.Limits.Subs) 131 require.Equal(t, int64(5), ac.Limits.Streams) 132 require.Equal(t, int64(6), ac.Limits.Consumer) 133 require.Equal(t, int64(7), ac.Limits.DiskStorage) 134 require.Equal(t, int64(8), ac.Limits.MemoryStorage) 135 require.Equal(t, int64(1024*1024*9), ac.Limits.DiskMaxStreamBytes) 136 require.Equal(t, int64(10), ac.Limits.MemoryMaxStreamBytes) 137 require.Equal(t, int64(11), ac.Limits.MaxAckPending) 138 require.True(t, ac.Limits.MaxBytesRequired) 139 } 140 141 func Test_EditJsOptionsOnTierDelete(t *testing.T) { 142 ts := NewTestStore(t, "edit account") 143 defer ts.Done(t) 144 145 ts.AddAccount(t, "A") 146 _, _, err := ExecuteCmd(createEditAccount(), 147 "--js-streams", "5", "--js-consumer", "6", "--js-disk-storage", "7") 148 require.NoError(t, err) 149 150 ac, err := ts.Store.ReadAccountClaim("A") 151 require.NoError(t, err) 152 require.Equal(t, int64(5), ac.Limits.Streams) 153 require.Equal(t, int64(6), ac.Limits.Consumer) 154 require.Equal(t, int64(7), ac.Limits.DiskStorage) 155 156 _, _, err = ExecuteCmd(createEditAccount(), 157 "--js-streams", "1", "--rm-js-tier", "0") 158 require.Error(t, err) 159 require.Equal(t, "rm-js-tier is exclusive of all other js options", err.Error()) 160 161 _, _, err = ExecuteCmd(createEditAccount(), 162 "--rm-js-tier", "0") 163 require.NoError(t, err) 164 ac, err = ts.Store.ReadAccountClaim("A") 165 require.NoError(t, err) 166 require.Equal(t, int64(0), ac.Limits.Streams) 167 require.Equal(t, int64(0), ac.Limits.Consumer) 168 require.Equal(t, int64(0), ac.Limits.DiskStorage) 169 } 170 171 func Test_GlobalPreventsTiered(t *testing.T) { 172 ts := NewTestStore(t, "edit account") 173 defer ts.Done(t) 174 175 ts.AddAccount(t, "A") 176 _, _, err := ExecuteCmd(createEditAccount(), 177 "--js-streams", "5", "--js-disk-storage", "10") 178 require.NoError(t, err) 179 180 ac, err := ts.Store.ReadAccountClaim("A") 181 require.NoError(t, err) 182 require.Equal(t, int64(5), ac.Limits.Streams) 183 184 _, _, err = ExecuteCmd(createEditAccount(), 185 "--js-tier", "1", "--js-disk-storage", "10") 186 require.Error(t, err) 187 require.Equal(t, "cannot set a jetstream tier limit when a configuration has a global limit", err.Error()) 188 } 189 190 func Test_TieredPreventsGlobal(t *testing.T) { 191 ts := NewTestStore(t, "edit account") 192 defer ts.Done(t) 193 194 ts.AddAccount(t, "A") 195 _, _, err := ExecuteCmd(createEditAccount(), 196 "--js-tier", "2", "--js-streams", "5", "--js-disk-storage", "10") 197 require.NoError(t, err) 198 199 ac, err := ts.Store.ReadAccountClaim("A") 200 require.NoError(t, err) 201 require.Equal(t, int64(5), ac.Limits.JetStreamTieredLimits["R2"].Streams) 202 203 _, _, err = ExecuteCmd(createEditAccount(), 204 "--js-disk-storage", "10") 205 require.Error(t, err) 206 require.Equal(t, "cannot set a jetstream global limit when a configuration has tiered limits 'R2'", err.Error()) 207 } 208 209 func Test_TieredDoesntPreventOtherClaims(t *testing.T) { 210 ts := NewTestStore(t, "edit account") 211 defer ts.Done(t) 212 213 ts.AddAccount(t, "A") 214 _, _, err := ExecuteCmd(createEditAccount(), 215 "--js-tier", "2", "--js-streams", "5", "--js-disk-storage", "10") 216 require.NoError(t, err) 217 218 ac, err := ts.Store.ReadAccountClaim("A") 219 require.NoError(t, err) 220 require.Equal(t, int64(5), ac.Limits.JetStreamTieredLimits["R2"].Streams) 221 222 _, _, err = ExecuteCmd(createEditAccount(), 223 "--sk", "generate") 224 require.NoError(t, err) 225 } 226 227 func Test_EditAccountSigningKeys(t *testing.T) { 228 ts := NewTestStore(t, "edit account") 229 defer ts.Done(t) 230 231 ts.AddAccount(t, "A") 232 _, pk, _ := CreateAccountKey(t) 233 _, pk2, _ := CreateAccountKey(t) 234 235 _, _, err := ExecuteCmd(createEditAccount(), "--sk", pk, "--sk", pk2) 236 require.NoError(t, err) 237 238 ac, err := ts.Store.ReadAccountClaim("A") 239 require.NoError(t, err) 240 require.Contains(t, ac.SigningKeys, pk) 241 require.Contains(t, ac.SigningKeys, pk2) 242 243 _, _, err = ExecuteCmd(createEditAccount(), "--rm-sk", pk) 244 require.NoError(t, err) 245 246 ac, err = ts.Store.ReadAccountClaim("A") 247 require.NoError(t, err) 248 require.NotContains(t, ac.SigningKeys, pk) 249 } 250 251 func Test_EditAccount_Pubs(t *testing.T) { 252 ts := NewTestStore(t, "edit user") 253 defer ts.Done(t) 254 255 ts.AddAccount(t, "A") 256 257 _, _, err := ExecuteCmd(createEditAccount(), "--allow-pub", "a,b", "--allow-pubsub", "c", "--deny-pub", "foo", "--deny-pubsub", "bar") 258 require.NoError(t, err) 259 260 cc, err := ts.Store.ReadAccountClaim("A") 261 require.NoError(t, err) 262 require.NotNil(t, cc) 263 require.ElementsMatch(t, cc.DefaultPermissions.Pub.Allow, []string{"a", "b", "c"}) 264 require.ElementsMatch(t, cc.DefaultPermissions.Sub.Allow, []string{"c"}) 265 require.ElementsMatch(t, cc.DefaultPermissions.Pub.Deny, []string{"foo", "bar"}) 266 require.ElementsMatch(t, cc.DefaultPermissions.Sub.Deny, []string{"bar"}) 267 268 _, _, err = ExecuteCmd(createEditAccount(), "--rm", "c,bar") 269 require.NoError(t, err) 270 cc, err = ts.Store.ReadAccountClaim("A") 271 require.NoError(t, err) 272 require.NotNil(t, cc) 273 274 require.ElementsMatch(t, cc.DefaultPermissions.Pub.Allow, []string{"a", "b"}) 275 require.Len(t, cc.DefaultPermissions.Sub.Allow, 0) 276 require.ElementsMatch(t, cc.DefaultPermissions.Pub.Deny, []string{"foo"}) 277 require.Len(t, cc.DefaultPermissions.Sub.Deny, 0) 278 } 279 280 func Test_EditAccountResponsePermissions(t *testing.T) { 281 ts := NewTestStore(t, "O") 282 defer ts.Done(t) 283 ts.AddAccount(t, "A") 284 285 _, _, err := ExecuteCmd(createEditAccount(), "--max-responses", "1000", "--response-ttl", "4ms") 286 require.NoError(t, err) 287 288 uc, err := ts.Store.ReadAccountClaim("A") 289 require.NoError(t, err) 290 require.NotNil(t, uc.DefaultPermissions.Resp) 291 require.Equal(t, 1000, uc.DefaultPermissions.Resp.MaxMsgs) 292 d, _ := time.ParseDuration("4ms") 293 require.Equal(t, d, uc.DefaultPermissions.Resp.Expires) 294 295 _, _, err = ExecuteCmd(createEditAccount(), "--rm-response-perms") 296 require.NoError(t, err) 297 298 uc, err = ts.Store.ReadAccountClaim("A") 299 require.NoError(t, err) 300 require.Nil(t, uc.DefaultPermissions.Resp) 301 } 302 303 func Test_EditAccountSk(t *testing.T) { 304 ts := NewTestStore(t, "O") 305 defer ts.Done(t) 306 307 sk, err := nkeys.CreateOperator() 308 require.NoError(t, err) 309 _, err = ts.KeyStore.Store(sk) 310 require.NoError(t, err) 311 pSk, err := sk.PublicKey() 312 require.NoError(t, err) 313 314 _, _, err = ExecuteCmd(createEditOperatorCmd(), "--sk", pSk) 315 require.NoError(t, err) 316 317 ts.AddAccountWithSigner(t, "A", sk) 318 ac, err := ts.Store.ReadAccountClaim("A") 319 require.NoError(t, err) 320 require.Equal(t, ac.Issuer, pSk) 321 322 _, _, err = ExecuteCmd(createEditAccount(), "--tag", "foo") 323 require.NoError(t, err) 324 ac, err = ts.Store.ReadAccountClaim("A") 325 require.NoError(t, err) 326 require.Equal(t, ac.Issuer, pSk) 327 } 328 329 func Test_EditOperatorDisallowBearerToken(t *testing.T) { 330 ts := NewTestStore(t, "O") 331 defer ts.Done(t) 332 ts.AddAccount(t, "A") 333 ts.AddUser(t, "A", "U") 334 335 _, _, err := ExecuteCmd(createEditUserCmd(), "--name", "U", "--bearer") 336 require.NoError(t, err) 337 338 _, _, err = ExecuteCmd(createEditAccount(), "--name", "A", "--disallow-bearer") 339 require.Error(t, err) 340 require.Equal(t, err.Error(), `user "U" in account "A" uses bearer token (needs to be deleted/changed first)`) 341 342 // delete offending user 343 _, _, err = ExecuteCmd(createDeleteUserCmd(), "--account", "A", "--name", "U") 344 require.NoError(t, err) 345 // set option 346 _, _, err = ExecuteCmd(createEditAccount(), "--name", "A", "--disallow-bearer") 347 require.NoError(t, err) 348 // test user creation 349 _, _, err = ExecuteCmd(CreateAddUserCmd(), "--account", "A", "--name", "U", "--bearer") 350 require.Error(t, err) 351 require.Equal(t, err.Error(), `account "A" forbids the use of bearer token`) 352 _, _, err = ExecuteCmd(CreateAddUserCmd(), "--account", "A", "--name", "U") 353 require.NoError(t, err) 354 _, _, err = ExecuteCmd(createEditUserCmd(), "--account", "A", "--name", "U", "--bearer") 355 require.Error(t, err) 356 require.Equal(t, err.Error(), "account disallows bearer token") 357 } 358 359 func Test_EditSysAccount(t *testing.T) { 360 ts := NewTestStore(t, "O") 361 defer ts.Done(t) 362 ts.AddAccount(t, "SYS") 363 _, _, err := ExecuteCmd(createEditOperatorCmd(), "--system-account", "SYS") 364 require.NoError(t, err) 365 366 // test setting any flag will generate an error and the flag is reported 367 jsOptions := []string{ 368 "js-max-bytes-required", 369 "js-tier", 370 "js-mem-storage", 371 "js-disk-storage", 372 "js-streams", 373 "js-consumer", 374 "js-max-mem-stream", 375 "js-max-disk-stream", 376 "js-max-ack-pending", 377 } 378 // setting any JS flags, will fail the edit 379 for idx, n := range jsOptions { 380 flag := fmt.Sprintf("--%s", n) 381 if idx > 0 { 382 _, _, err = ExecuteCmd(createEditAccount(), "SYS", "--tag", "A", flag, "1") 383 require.Error(t, err) 384 require.Contains(t, err.Error(), flag) 385 } else { 386 _, _, err = ExecuteCmd(createEditAccount(), "SYS", "--tag", "A", flag) 387 require.Error(t, err) 388 require.Contains(t, err.Error(), flag) 389 } 390 } 391 // defaults are removed automatically 392 _, _, err = ExecuteCmd(createEditAccount(), "SYS", "--tag", "A") 393 require.NoError(t, err) 394 } 395 396 func Test_TierRmAndDisabled(t *testing.T) { 397 ts := NewTestStore(t, "O") 398 defer ts.Done(t) 399 ts.AddAccount(t, "A") 400 401 _, _, err := ExecuteCmd(createEditAccount(), "A", "--rm-js-tier", "1", "--js-disable") 402 require.Error(t, err) 403 require.Equal(t, err.Error(), "js-disable is exclusive of all other js options") 404 } 405 406 func Test_TracingSampling(t *testing.T) { 407 ts := NewTestStore(t, "O") 408 defer ts.Done(t) 409 ts.AddAccount(t, "A") 410 411 // cannot set sampling if no subject 412 _, _, err := ExecuteCmd(createEditAccount(), "A", "--trace-context-sampling", "50") 413 require.Error(t, err) 414 require.Equal(t, "trace-context-sampling requires a subject", err.Error()) 415 416 // set a subject 417 _, _, err = ExecuteCmd(createEditAccount(), "A", "--trace-context-subject", "traces") 418 require.NoError(t, err) 419 420 // range checks 421 _, _, err = ExecuteCmd(createEditAccount(), "A", "--trace-context-sampling", "101") 422 require.Error(t, err) 423 require.Equal(t, "tracing sampling rate must be between 1-100", err.Error()) 424 425 _, _, err = ExecuteCmd(createEditAccount(), "A", "--trace-context-sampling", "-1") 426 require.Error(t, err) 427 require.Equal(t, "tracing sampling rate must be between 1-100", err.Error()) 428 429 // disable and set 430 _, _, err = ExecuteCmd(createEditAccount(), "A", "--trace-context-sampling", "50", "--trace-context-subject", "") 431 require.Error(t, err) 432 require.Equal(t, "cannot set context sampling rate when disabling the trace context", err.Error()) 433 } 434 435 func Test_TracingSubject(t *testing.T) { 436 ts := NewTestStore(t, "O") 437 defer ts.Done(t) 438 ts.AddAccount(t, "A") 439 440 ac, err := ts.Store.ReadAccountClaim("A") 441 require.NoError(t, err) 442 require.Nil(t, ac.Trace) 443 444 // no op 445 _, _, err = ExecuteCmd(createEditAccount(), "A", "--trace-context-subject", "") 446 require.NoError(t, err) 447 448 // bad subjects are checked by jwt lib, just making sure we are catching 449 _, _, err = ExecuteCmd(createEditAccount(), "A", "--trace-context-subject", "traces.*") 450 require.Error(t, err) 451 require.Equal(t, "tracing subjects cannot contain wildcards: \"traces.*\"", err.Error()) 452 453 _, _, err = ExecuteCmd(createEditAccount(), "A", "--trace-context-subject", "traces.here") 454 require.NoError(t, err) 455 456 ac, err = ts.Store.ReadAccountClaim("A") 457 require.NoError(t, err) 458 require.NotNil(t, ac.Trace) 459 require.Equal(t, jwt.Subject("traces.here"), ac.Trace.Destination) 460 require.Equal(t, 0, ac.Trace.Sampling) 461 462 // we have a subject, so set the sampling 463 _, _, err = ExecuteCmd(createEditAccount(), "A", "--trace-context-sampling", "75") 464 require.NoError(t, err) 465 466 ac, err = ts.Store.ReadAccountClaim("A") 467 require.NoError(t, err) 468 require.NotNil(t, ac.Trace) 469 require.Equal(t, jwt.Subject("traces.here"), ac.Trace.Destination) 470 require.Equal(t, 75, ac.Trace.Sampling) 471 472 _, _, err = ExecuteCmd(createEditAccount(), "A", "--trace-context-subject", "") 473 require.NoError(t, err) 474 ac, err = ts.Store.ReadAccountClaim("A") 475 require.NoError(t, err) 476 require.Nil(t, ac.Trace) 477 } 478 479 func Test_EnableTier(t *testing.T) { 480 ts := NewTestStore(t, "O") 481 defer ts.Done(t) 482 ts.AddAccount(t, "A") 483 484 ac, err := ts.Store.ReadAccountClaim("A") 485 require.NoError(t, err) 486 require.Equal(t, ac.Limits.JetStreamLimits, jwt.JetStreamLimits{}) 487 488 _, _, err = ExecuteCmd(createEditAccount(), "A", "--js-enable", "0") 489 require.NoError(t, err) 490 491 ac, err = ts.Store.ReadAccountClaim("A") 492 require.NoError(t, err) 493 require.Equal(t, ac.Limits.JetStreamLimits, jwt.JetStreamLimits{DiskStorage: -1, MemoryStorage: -1}) 494 } 495 496 func Test_EnableTierDoesntClobber(t *testing.T) { 497 ts := NewTestStore(t, "O") 498 defer ts.Done(t) 499 ts.AddAccount(t, "A") 500 501 ac, err := ts.Store.ReadAccountClaim("A") 502 require.NoError(t, err) 503 require.Equal(t, ac.Limits.JetStreamLimits, jwt.JetStreamLimits{}) 504 505 _, _, err = ExecuteCmd(createEditAccount(), "A", "--js-enable", "0") 506 require.NoError(t, err) 507 508 _, _, err = ExecuteCmd(createEditAccount(), "A", "--js-enable", "0") 509 require.Error(t, err) 510 require.Equal(t, "jetstream tier global is already enabled", err.Error()) 511 } 512 513 func Test_EnableTierNoOtherFlag(t *testing.T) { 514 ts := NewTestStore(t, "O") 515 defer ts.Done(t) 516 ts.AddAccount(t, "A") 517 518 ac, err := ts.Store.ReadAccountClaim("A") 519 require.NoError(t, err) 520 require.Equal(t, ac.Limits.JetStreamLimits, jwt.JetStreamLimits{}) 521 522 _, _, err = ExecuteCmd(createEditAccount(), "A", "--js-enable", "0", "--rm-js-tier", "0") 523 require.Error(t, err) 524 require.Equal(t, "rm-js-tier is exclusive of all other js options", err.Error()) 525 }