1package vault_test 2 3import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "testing" 9 "time" 10 11 "github.com/go-test/deep" 12 "github.com/hashicorp/vault/api" 13 "github.com/hashicorp/vault/builtin/plugin" 14 "github.com/hashicorp/vault/helper/namespace" 15 vaulthttp "github.com/hashicorp/vault/http" 16 "github.com/hashicorp/vault/sdk/helper/consts" 17 "github.com/hashicorp/vault/sdk/helper/pluginutil" 18 "github.com/hashicorp/vault/sdk/logical" 19 lplugin "github.com/hashicorp/vault/sdk/plugin" 20 "github.com/hashicorp/vault/sdk/plugin/mock" 21 "github.com/hashicorp/vault/vault" 22) 23 24const ( 25 expectedEnvKey = "FOO" 26 expectedEnvValue = "BAR" 27) 28 29func TestSystemBackend_Plugin_secret(t *testing.T) { 30 cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical) 31 defer cluster.Cleanup() 32 33 core := cluster.Cores[0] 34 35 // Make a request to lazy load the plugin 36 req := logical.TestRequest(t, logical.ReadOperation, "mock-0/internal") 37 req.ClientToken = core.Client.Token() 38 resp, err := core.HandleRequest(namespace.RootContext(nil), req) 39 if err != nil { 40 t.Fatalf("err: %v", err) 41 } 42 if resp == nil { 43 t.Fatalf("bad: response should not be nil") 44 } 45 46 // Seal the cluster 47 cluster.EnsureCoresSealed(t) 48 49 // Unseal the cluster 50 barrierKeys := cluster.BarrierKeys 51 for _, core := range cluster.Cores { 52 for _, key := range barrierKeys { 53 _, err := core.Unseal(vault.TestKeyCopy(key)) 54 if err != nil { 55 t.Fatal(err) 56 } 57 } 58 if core.Sealed() { 59 t.Fatal("should not be sealed") 60 } 61 // Wait for active so post-unseal takes place 62 // If it fails, it means unseal process failed 63 vault.TestWaitActive(t, core.Core) 64 } 65} 66 67func TestSystemBackend_Plugin_auth(t *testing.T) { 68 cluster := testSystemBackendMock(t, 1, 1, logical.TypeCredential) 69 defer cluster.Cleanup() 70 71 core := cluster.Cores[0] 72 73 // Make a request to lazy load the plugin 74 req := logical.TestRequest(t, logical.ReadOperation, "auth/mock-0/internal") 75 req.ClientToken = core.Client.Token() 76 resp, err := core.HandleRequest(namespace.RootContext(nil), req) 77 if err != nil { 78 t.Fatalf("err: %v", err) 79 } 80 if resp == nil { 81 t.Fatalf("bad: response should not be nil") 82 } 83 84 // Seal the cluster 85 cluster.EnsureCoresSealed(t) 86 87 // Unseal the cluster 88 barrierKeys := cluster.BarrierKeys 89 for _, core := range cluster.Cores { 90 for _, key := range barrierKeys { 91 _, err := core.Unseal(vault.TestKeyCopy(key)) 92 if err != nil { 93 t.Fatal(err) 94 } 95 } 96 if core.Sealed() { 97 t.Fatal("should not be sealed") 98 } 99 // Wait for active so post-unseal takes place 100 // If it fails, it means unseal process failed 101 vault.TestWaitActive(t, core.Core) 102 } 103} 104 105func TestSystemBackend_Plugin_MismatchType(t *testing.T) { 106 cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical) 107 defer cluster.Cleanup() 108 109 core := cluster.Cores[0] 110 111 // Add a credential backend with the same name 112 vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeCredential, "TestBackend_PluginMainCredentials", []string{}, "") 113 114 // Make a request to lazy load the now-credential plugin 115 // and expect an error 116 req := logical.TestRequest(t, logical.ReadOperation, "mock-0/internal") 117 req.ClientToken = core.Client.Token() 118 _, err := core.HandleRequest(namespace.RootContext(nil), req) 119 if err != nil { 120 t.Fatalf("adding a same-named plugin of a different type should be no problem: %s", err) 121 } 122 123 // Sleep a bit before cleanup is called 124 time.Sleep(1 * time.Second) 125} 126 127func TestSystemBackend_Plugin_CatalogRemoved(t *testing.T) { 128 t.Run("secret", func(t *testing.T) { 129 testPlugin_CatalogRemoved(t, logical.TypeLogical, false) 130 }) 131 132 t.Run("auth", func(t *testing.T) { 133 testPlugin_CatalogRemoved(t, logical.TypeCredential, false) 134 }) 135 136 t.Run("secret-mount-existing", func(t *testing.T) { 137 testPlugin_CatalogRemoved(t, logical.TypeLogical, true) 138 }) 139 140 t.Run("auth-mount-existing", func(t *testing.T) { 141 testPlugin_CatalogRemoved(t, logical.TypeCredential, true) 142 }) 143} 144 145func testPlugin_CatalogRemoved(t *testing.T, btype logical.BackendType, testMount bool) { 146 cluster := testSystemBackendMock(t, 1, 1, btype) 147 defer cluster.Cleanup() 148 149 core := cluster.Cores[0] 150 151 // Remove the plugin from the catalog 152 req := logical.TestRequest(t, logical.DeleteOperation, "sys/plugins/catalog/database/mock-plugin") 153 req.ClientToken = core.Client.Token() 154 resp, err := core.HandleRequest(namespace.RootContext(nil), req) 155 if err != nil || (resp != nil && resp.IsError()) { 156 t.Fatalf("err:%v resp:%#v", err, resp) 157 } 158 159 // Seal the cluster 160 cluster.EnsureCoresSealed(t) 161 162 // Unseal the cluster 163 barrierKeys := cluster.BarrierKeys 164 for _, core := range cluster.Cores { 165 for _, key := range barrierKeys { 166 _, err := core.Unseal(vault.TestKeyCopy(key)) 167 if err != nil { 168 t.Fatal(err) 169 } 170 } 171 if core.Sealed() { 172 t.Fatal("should not be sealed") 173 } 174 } 175 176 // Wait for active so post-unseal takes place 177 // If it fails, it means unseal process failed 178 vault.TestWaitActive(t, core.Core) 179 180 if testMount { 181 // Mount the plugin at the same path after plugin is re-added to the catalog 182 // and expect an error due to existing path. 183 var err error 184 switch btype { 185 case logical.TypeLogical: 186 // Add plugin back to the catalog 187 vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeSecrets, "TestBackend_PluginMainLogical", []string{}, "") 188 _, err = core.Client.Logical().Write("sys/mounts/mock-0", map[string]interface{}{ 189 "type": "test", 190 }) 191 case logical.TypeCredential: 192 // Add plugin back to the catalog 193 vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeCredential, "TestBackend_PluginMainCredentials", []string{}, "") 194 _, err = core.Client.Logical().Write("sys/auth/mock-0", map[string]interface{}{ 195 "type": "test", 196 }) 197 } 198 if err == nil { 199 t.Fatal("expected error when mounting on existing path") 200 } 201 } 202} 203 204func TestSystemBackend_Plugin_continueOnError(t *testing.T) { 205 t.Run("secret", func(t *testing.T) { 206 t.Run("sha256_mismatch", func(t *testing.T) { 207 testPlugin_continueOnError(t, logical.TypeLogical, true, consts.PluginTypeSecrets) 208 }) 209 210 t.Run("missing_plugin", func(t *testing.T) { 211 testPlugin_continueOnError(t, logical.TypeLogical, false, consts.PluginTypeSecrets) 212 }) 213 }) 214 215 t.Run("auth", func(t *testing.T) { 216 t.Run("sha256_mismatch", func(t *testing.T) { 217 testPlugin_continueOnError(t, logical.TypeCredential, true, consts.PluginTypeCredential) 218 }) 219 220 t.Run("missing_plugin", func(t *testing.T) { 221 testPlugin_continueOnError(t, logical.TypeCredential, false, consts.PluginTypeCredential) 222 }) 223 }) 224} 225 226func testPlugin_continueOnError(t *testing.T, btype logical.BackendType, mismatch bool, pluginType consts.PluginType) { 227 cluster := testSystemBackendMock(t, 1, 1, btype) 228 defer cluster.Cleanup() 229 230 core := cluster.Cores[0] 231 232 // Get the registered plugin 233 req := logical.TestRequest(t, logical.ReadOperation, fmt.Sprintf("sys/plugins/catalog/%s/mock-plugin", pluginType)) 234 req.ClientToken = core.Client.Token() 235 resp, err := core.HandleRequest(namespace.RootContext(nil), req) 236 if err != nil || resp == nil || (resp != nil && resp.IsError()) { 237 t.Fatalf("err:%v resp:%#v", err, resp) 238 } 239 240 command, ok := resp.Data["command"].(string) 241 if !ok || command == "" { 242 t.Fatal("invalid command") 243 } 244 245 // Trigger a sha256 mismatch or missing plugin error 246 if mismatch { 247 req = logical.TestRequest(t, logical.UpdateOperation, "sys/plugins/catalog/database/mock-plugin") 248 req.Data = map[string]interface{}{ 249 "sha256": "d17bd7334758e53e6fbab15745d2520765c06e296f2ce8e25b7919effa0ac216", 250 "command": filepath.Base(command), 251 } 252 req.ClientToken = core.Client.Token() 253 resp, err = core.HandleRequest(namespace.RootContext(nil), req) 254 if err != nil || (resp != nil && resp.IsError()) { 255 t.Fatalf("err:%v resp:%#v", err, resp) 256 } 257 } else { 258 err := os.Remove(filepath.Join(cluster.TempDir, filepath.Base(command))) 259 if err != nil { 260 t.Fatal(err) 261 } 262 } 263 264 // Seal the cluster 265 cluster.EnsureCoresSealed(t) 266 267 // Unseal the cluster 268 barrierKeys := cluster.BarrierKeys 269 for _, core := range cluster.Cores { 270 for _, key := range barrierKeys { 271 _, err := core.Unseal(vault.TestKeyCopy(key)) 272 if err != nil { 273 t.Fatal(err) 274 } 275 } 276 if core.Sealed() { 277 t.Fatal("should not be sealed") 278 } 279 } 280 281 // Wait for active so post-unseal takes place 282 // If it fails, it means unseal process failed 283 vault.TestWaitActive(t, core.Core) 284 285 // Re-add the plugin to the catalog 286 switch btype { 287 case logical.TypeLogical: 288 vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeSecrets, "TestBackend_PluginMainLogical", []string{}, cluster.TempDir) 289 case logical.TypeCredential: 290 vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeCredential, "TestBackend_PluginMainCredentials", []string{}, cluster.TempDir) 291 } 292 293 // Reload the plugin 294 req = logical.TestRequest(t, logical.UpdateOperation, "sys/plugins/reload/backend") 295 req.Data = map[string]interface{}{ 296 "plugin": "mock-plugin", 297 } 298 req.ClientToken = core.Client.Token() 299 resp, err = core.HandleRequest(namespace.RootContext(nil), req) 300 if err != nil || (resp != nil && resp.IsError()) { 301 t.Fatalf("err:%v resp:%#v", err, resp) 302 } 303 304 // Make a request to lazy load the plugin 305 var reqPath string 306 switch btype { 307 case logical.TypeLogical: 308 reqPath = "mock-0/internal" 309 case logical.TypeCredential: 310 reqPath = "auth/mock-0/internal" 311 } 312 313 req = logical.TestRequest(t, logical.ReadOperation, reqPath) 314 req.ClientToken = core.Client.Token() 315 resp, err = core.HandleRequest(namespace.RootContext(nil), req) 316 if err != nil { 317 t.Fatalf("err: %v", err) 318 } 319 if resp == nil { 320 t.Fatalf("bad: response should not be nil") 321 } 322} 323 324func TestSystemBackend_Plugin_autoReload(t *testing.T) { 325 cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical) 326 defer cluster.Cleanup() 327 328 core := cluster.Cores[0] 329 330 // Update internal value 331 req := logical.TestRequest(t, logical.UpdateOperation, "mock-0/internal") 332 req.ClientToken = core.Client.Token() 333 req.Data["value"] = "baz" 334 resp, err := core.HandleRequest(namespace.RootContext(nil), req) 335 if err != nil { 336 t.Fatalf("err: %v", err) 337 } 338 if resp != nil { 339 t.Fatalf("bad: %v", resp) 340 } 341 342 // Call errors/rpc endpoint to trigger reload 343 req = logical.TestRequest(t, logical.ReadOperation, "mock-0/errors/rpc") 344 req.ClientToken = core.Client.Token() 345 resp, err = core.HandleRequest(namespace.RootContext(nil), req) 346 if err == nil { 347 t.Fatalf("expected error from error/rpc request") 348 } 349 350 // Check internal value to make sure it's reset 351 req = logical.TestRequest(t, logical.ReadOperation, "mock-0/internal") 352 req.ClientToken = core.Client.Token() 353 resp, err = core.HandleRequest(namespace.RootContext(nil), req) 354 if err != nil { 355 t.Fatalf("err: %v", err) 356 } 357 if resp == nil { 358 t.Fatalf("bad: response should not be nil") 359 } 360 if resp.Data["value"].(string) == "baz" { 361 t.Fatal("did not expect backend internal value to be 'baz'") 362 } 363} 364 365func TestSystemBackend_Plugin_SealUnseal(t *testing.T) { 366 cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical) 367 defer cluster.Cleanup() 368 369 // Seal the cluster 370 cluster.EnsureCoresSealed(t) 371 372 // Unseal the cluster 373 barrierKeys := cluster.BarrierKeys 374 for _, core := range cluster.Cores { 375 for _, key := range barrierKeys { 376 _, err := core.Unseal(vault.TestKeyCopy(key)) 377 if err != nil { 378 t.Fatal(err) 379 } 380 } 381 if core.Sealed() { 382 t.Fatal("should not be sealed") 383 } 384 } 385 386 // Wait for active so post-unseal takes place 387 // If it fails, it means unseal process failed 388 vault.TestWaitActive(t, cluster.Cores[0].Core) 389} 390 391func TestSystemBackend_Plugin_reload(t *testing.T) { 392 data := map[string]interface{}{ 393 "plugin": "mock-plugin", 394 } 395 t.Run("plugin", func(t *testing.T) { testSystemBackend_PluginReload(t, data) }) 396 397 data = map[string]interface{}{ 398 "mounts": "mock-0/,mock-1/", 399 } 400 t.Run("mounts", func(t *testing.T) { testSystemBackend_PluginReload(t, data) }) 401} 402 403// Helper func to test different reload methods on plugin reload endpoint 404func testSystemBackend_PluginReload(t *testing.T, reqData map[string]interface{}) { 405 cluster := testSystemBackendMock(t, 1, 2, logical.TypeLogical) 406 defer cluster.Cleanup() 407 408 core := cluster.Cores[0] 409 client := core.Client 410 411 for i := 0; i < 2; i++ { 412 // Update internal value in the backend 413 resp, err := client.Logical().Write(fmt.Sprintf("mock-%d/internal", i), map[string]interface{}{ 414 "value": "baz", 415 }) 416 if err != nil { 417 t.Fatalf("err: %v", err) 418 } 419 if resp != nil { 420 t.Fatalf("bad: %v", resp) 421 } 422 } 423 424 // Perform plugin reload 425 resp, err := client.Logical().Write("sys/plugins/reload/backend", reqData) 426 if err != nil { 427 t.Fatalf("err: %v", err) 428 } 429 if resp != nil { 430 t.Fatalf("bad: %v", resp) 431 } 432 433 for i := 0; i < 2; i++ { 434 // Ensure internal backed value is reset 435 resp, err := client.Logical().Read(fmt.Sprintf("mock-%d/internal", i)) 436 if err != nil { 437 t.Fatalf("err: %v", err) 438 } 439 if resp == nil { 440 t.Fatalf("bad: response should not be nil") 441 } 442 if resp.Data["value"].(string) == "baz" { 443 t.Fatal("did not expect backend internal value to be 'baz'") 444 } 445 } 446} 447 448// testSystemBackendMock returns a systemBackend with the desired number 449// of mounted mock plugin backends. numMounts alternates between different 450// ways of providing the plugin_name. 451// 452// The mounts are mounted at sys/mounts/mock-[numMounts] or sys/auth/mock-[numMounts] 453func testSystemBackendMock(t *testing.T, numCores, numMounts int, backendType logical.BackendType) *vault.TestCluster { 454 coreConfig := &vault.CoreConfig{ 455 LogicalBackends: map[string]logical.Factory{ 456 "plugin": plugin.Factory, 457 }, 458 CredentialBackends: map[string]logical.Factory{ 459 "plugin": plugin.Factory, 460 }, 461 } 462 463 // Create a tempdir, cluster.Cleanup will clean up this directory 464 tempDir, err := ioutil.TempDir("", "vault-test-cluster") 465 if err != nil { 466 t.Fatal(err) 467 } 468 469 cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{ 470 HandlerFunc: vaulthttp.Handler, 471 KeepStandbysSealed: true, 472 NumCores: numCores, 473 TempDir: tempDir, 474 }) 475 cluster.Start() 476 477 core := cluster.Cores[0] 478 vault.TestWaitActive(t, core.Core) 479 client := core.Client 480 481 os.Setenv(pluginutil.PluginCACertPEMEnv, cluster.CACertPEMFile) 482 483 switch backendType { 484 case logical.TypeLogical: 485 vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeSecrets, "TestBackend_PluginMainLogical", []string{}, tempDir) 486 for i := 0; i < numMounts; i++ { 487 // Alternate input styles for plugin_name on every other mount 488 options := map[string]interface{}{ 489 "type": "mock-plugin", 490 } 491 resp, err := client.Logical().Write(fmt.Sprintf("sys/mounts/mock-%d", i), options) 492 if err != nil { 493 t.Fatalf("err: %v", err) 494 } 495 if resp != nil { 496 t.Fatalf("bad: %v", resp) 497 } 498 } 499 case logical.TypeCredential: 500 vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeCredential, "TestBackend_PluginMainCredentials", []string{}, tempDir) 501 for i := 0; i < numMounts; i++ { 502 // Alternate input styles for plugin_name on every other mount 503 options := map[string]interface{}{ 504 "type": "mock-plugin", 505 } 506 resp, err := client.Logical().Write(fmt.Sprintf("sys/auth/mock-%d", i), options) 507 if err != nil { 508 t.Fatalf("err: %v", err) 509 } 510 if resp != nil { 511 t.Fatalf("bad: %v", resp) 512 } 513 } 514 default: 515 t.Fatal("unknown backend type provided") 516 } 517 518 return cluster 519} 520 521func TestSystemBackend_Plugin_Env(t *testing.T) { 522 kvPair := fmt.Sprintf("%s=%s", expectedEnvKey, expectedEnvValue) 523 cluster := testSystemBackend_SingleCluster_Env(t, []string{kvPair}) 524 defer cluster.Cleanup() 525} 526 527// testSystemBackend_SingleCluster_Env is a helper func that returns a single 528// cluster and a single mounted plugin logical backend. 529func testSystemBackend_SingleCluster_Env(t *testing.T, env []string) *vault.TestCluster { 530 coreConfig := &vault.CoreConfig{ 531 LogicalBackends: map[string]logical.Factory{ 532 "test": plugin.Factory, 533 }, 534 } 535 536 // Create a tempdir, cluster.Cleanup will clean up this directory 537 tempDir, err := ioutil.TempDir("", "vault-test-cluster") 538 if err != nil { 539 t.Fatal(err) 540 } 541 542 cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{ 543 HandlerFunc: vaulthttp.Handler, 544 KeepStandbysSealed: true, 545 NumCores: 1, 546 TempDir: tempDir, 547 }) 548 cluster.Start() 549 550 core := cluster.Cores[0] 551 vault.TestWaitActive(t, core.Core) 552 client := core.Client 553 554 os.Setenv(pluginutil.PluginCACertPEMEnv, cluster.CACertPEMFile) 555 556 vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeSecrets, "TestBackend_PluginMainEnv", env, tempDir) 557 options := map[string]interface{}{ 558 "type": "mock-plugin", 559 } 560 561 resp, err := client.Logical().Write("sys/mounts/mock", options) 562 if err != nil { 563 t.Fatalf("err: %v", err) 564 } 565 if resp != nil { 566 t.Fatalf("bad: %v", resp) 567 } 568 569 return cluster 570} 571 572func TestBackend_PluginMainLogical(t *testing.T) { 573 args := []string{} 574 if os.Getenv(pluginutil.PluginUnwrapTokenEnv) == "" && os.Getenv(pluginutil.PluginMetadataModeEnv) != "true" { 575 return 576 } 577 578 caPEM := os.Getenv(pluginutil.PluginCACertPEMEnv) 579 if caPEM == "" { 580 t.Fatal("CA cert not passed in") 581 } 582 args = append(args, fmt.Sprintf("--ca-cert=%s", caPEM)) 583 584 apiClientMeta := &api.PluginAPIClientMeta{} 585 flags := apiClientMeta.FlagSet() 586 flags.Parse(args) 587 tlsConfig := apiClientMeta.GetTLSConfig() 588 tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) 589 590 factoryFunc := mock.FactoryType(logical.TypeLogical) 591 592 err := lplugin.Serve(&lplugin.ServeOpts{ 593 BackendFactoryFunc: factoryFunc, 594 TLSProviderFunc: tlsProviderFunc, 595 }) 596 if err != nil { 597 t.Fatal(err) 598 } 599} 600 601func TestBackend_PluginMainCredentials(t *testing.T) { 602 args := []string{} 603 if os.Getenv(pluginutil.PluginUnwrapTokenEnv) == "" && os.Getenv(pluginutil.PluginMetadataModeEnv) != "true" { 604 return 605 } 606 607 caPEM := os.Getenv(pluginutil.PluginCACertPEMEnv) 608 if caPEM == "" { 609 t.Fatal("CA cert not passed in") 610 } 611 args = append(args, fmt.Sprintf("--ca-cert=%s", caPEM)) 612 613 apiClientMeta := &api.PluginAPIClientMeta{} 614 flags := apiClientMeta.FlagSet() 615 flags.Parse(args) 616 tlsConfig := apiClientMeta.GetTLSConfig() 617 tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) 618 619 factoryFunc := mock.FactoryType(logical.TypeCredential) 620 621 err := lplugin.Serve(&lplugin.ServeOpts{ 622 BackendFactoryFunc: factoryFunc, 623 TLSProviderFunc: tlsProviderFunc, 624 }) 625 if err != nil { 626 t.Fatal(err) 627 } 628} 629 630// TestBackend_PluginMainEnv is a mock plugin that simply checks for the existence of FOO env var. 631func TestBackend_PluginMainEnv(t *testing.T) { 632 args := []string{} 633 if os.Getenv(pluginutil.PluginUnwrapTokenEnv) == "" && os.Getenv(pluginutil.PluginMetadataModeEnv) != "true" { 634 return 635 } 636 637 // Check on actual vs expected env var 638 actual := os.Getenv(expectedEnvKey) 639 if actual != expectedEnvValue { 640 t.Fatalf("expected: %q, got: %q", expectedEnvValue, actual) 641 } 642 643 caPEM := os.Getenv(pluginutil.PluginCACertPEMEnv) 644 if caPEM == "" { 645 t.Fatal("CA cert not passed in") 646 } 647 args = append(args, fmt.Sprintf("--ca-cert=%s", caPEM)) 648 649 apiClientMeta := &api.PluginAPIClientMeta{} 650 flags := apiClientMeta.FlagSet() 651 flags.Parse(args) 652 tlsConfig := apiClientMeta.GetTLSConfig() 653 tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) 654 655 factoryFunc := mock.FactoryType(logical.TypeLogical) 656 657 err := lplugin.Serve(&lplugin.ServeOpts{ 658 BackendFactoryFunc: factoryFunc, 659 TLSProviderFunc: tlsProviderFunc, 660 }) 661 if err != nil { 662 t.Fatal(err) 663 } 664} 665 666func TestSystemBackend_InternalUIResultantACL(t *testing.T) { 667 cluster := vault.NewTestCluster(t, nil, &vault.TestClusterOptions{ 668 HandlerFunc: vaulthttp.Handler, 669 }) 670 cluster.Start() 671 defer cluster.Cleanup() 672 client := cluster.Cores[0].Client 673 674 resp, err := client.Auth().Token().Create(&api.TokenCreateRequest{ 675 Policies: []string{"default"}, 676 }) 677 if err != nil { 678 t.Fatal(err) 679 } 680 if resp == nil { 681 t.Fatal("nil response") 682 } 683 if resp.Auth == nil { 684 t.Fatal("nil auth") 685 } 686 if resp.Auth.ClientToken == "" { 687 t.Fatal("empty client token") 688 } 689 690 client.SetToken(resp.Auth.ClientToken) 691 692 resp, err = client.Logical().Read("sys/internal/ui/resultant-acl") 693 if err != nil { 694 t.Fatal(err) 695 } 696 if resp == nil { 697 t.Fatal("nil response") 698 } 699 if resp.Data == nil { 700 t.Fatal("nil data") 701 } 702 703 exp := map[string]interface{}{ 704 "exact_paths": map[string]interface{}{ 705 "auth/token/lookup-self": map[string]interface{}{ 706 "capabilities": []interface{}{ 707 "read", 708 }, 709 }, 710 "auth/token/renew-self": map[string]interface{}{ 711 "capabilities": []interface{}{ 712 "update", 713 }, 714 }, 715 "auth/token/revoke-self": map[string]interface{}{ 716 "capabilities": []interface{}{ 717 "update", 718 }, 719 }, 720 "sys/capabilities-self": map[string]interface{}{ 721 "capabilities": []interface{}{ 722 "update", 723 }, 724 }, 725 "sys/control-group/request": map[string]interface{}{ 726 "capabilities": []interface{}{ 727 "update", 728 }, 729 }, 730 "sys/internal/ui/resultant-acl": map[string]interface{}{ 731 "capabilities": []interface{}{ 732 "read", 733 }, 734 }, 735 "sys/leases/lookup": map[string]interface{}{ 736 "capabilities": []interface{}{ 737 "update", 738 }, 739 }, 740 "sys/leases/renew": map[string]interface{}{ 741 "capabilities": []interface{}{ 742 "update", 743 }, 744 }, 745 "sys/renew": map[string]interface{}{ 746 "capabilities": []interface{}{ 747 "update", 748 }, 749 }, 750 "sys/tools/hash": map[string]interface{}{ 751 "capabilities": []interface{}{ 752 "update", 753 }, 754 }, 755 "sys/wrapping/lookup": map[string]interface{}{ 756 "capabilities": []interface{}{ 757 "update", 758 }, 759 }, 760 "sys/wrapping/unwrap": map[string]interface{}{ 761 "capabilities": []interface{}{ 762 "update", 763 }, 764 }, 765 "sys/wrapping/wrap": map[string]interface{}{ 766 "capabilities": []interface{}{ 767 "update", 768 }, 769 }, 770 }, 771 "glob_paths": map[string]interface{}{ 772 "cubbyhole/": map[string]interface{}{ 773 "capabilities": []interface{}{ 774 "create", 775 "delete", 776 "list", 777 "read", 778 "update", 779 }, 780 }, 781 "sys/tools/hash/": map[string]interface{}{ 782 "capabilities": []interface{}{ 783 "update", 784 }, 785 }, 786 }, 787 "root": false, 788 } 789 790 if diff := deep.Equal(resp.Data, exp); diff != nil { 791 t.Fatal(diff) 792 } 793} 794