// Mount is used to expose a logical backend at a given prefix, using a unique salt, // and the barrier view for that path. func (r *Router) Mount(backend logical.Backend, prefix, salt string, view *BarrierView) error { r.l.Lock() defer r.l.Unlock() // Check if this is a nested mount if existing, _, ok := r.root.LongestPrefix(prefix); ok && existing != "" { return fmt.Errorf("cannot mount under existing mount '%s'", existing) } // Build the paths paths := backend.SpecialPaths() if paths == nil { paths = new(logical.Paths) } // Create a mount entry me := &mountEntry{ tainted: false, backend: backend, view: view, rootPaths: pathsToRadix(paths.Root), loginPaths: pathsToRadix(paths.Unauthenticated), } r.root.Insert(prefix, me) return nil }
func TestPathMap(t *testing.T) { p := &PathMap{Name: "foo"} storage := new(logical.InmemStorage) var b logical.Backend = &Backend{Paths: p.Paths()} // Write via HTTP _, err := b.HandleRequest(&logical.Request{ Operation: logical.WriteOperation, Path: "map/foo/a", Data: map[string]interface{}{ "value": "bar", }, Storage: storage, }) if err != nil { t.Fatalf("bad: %#v", err) } // Read via HTTP resp, err := b.HandleRequest(&logical.Request{ Operation: logical.ReadOperation, Path: "map/foo/a", Storage: storage, }) if err != nil { t.Fatalf("bad: %#v", err) } if resp.Data["value"] != "bar" { t.Fatalf("bad: %#v", resp) } // Read via API v, err := p.Get(storage, "a") if err != nil { t.Fatalf("bad: %#v", err) } if v["value"] != "bar" { t.Fatalf("bad: %#v", v) } // Read via API with other casing v, err = p.Get(storage, "A") if err != nil { t.Fatalf("bad: %#v", err) } if v["value"] != "bar" { t.Fatalf("bad: %#v", v) } // Verify List keys, err := p.List(storage, "") if err != nil { t.Fatalf("bad: %#v", err) } if len(keys) != 1 || keys[0] != "a" { t.Fatalf("bad: %#v", keys) } }
func testAccStepReadCreds(t *testing.T, b logical.Backend, name string) logicaltest.TestStep { return logicaltest.TestStep{ Operation: logical.ReadOperation, Path: "creds/" + name, Check: func(resp *logical.Response) error { var d struct { Username string `mapstructure:"username"` Password string `mapstructure:"password"` } if err := mapstructure.Decode(resp.Data, &d); err != nil { return err } log.Printf("[WARN] Generated credentials: %v", d) uri := os.Getenv(envRabbitMQConnectionURI) client, err := rabbithole.NewClient(uri, d.Username, d.Password) if err != nil { t.Fatal(err) } _, err = client.ListVhosts() if err != nil { t.Fatalf("unable to list vhosts with generated credentials: %s", err) } resp, err = b.HandleRequest(&logical.Request{ Operation: logical.RevokeOperation, Secret: &logical.Secret{ InternalData: map[string]interface{}{ "secret_type": "creds", "username": d.Username, }, }, }) if err != nil { return err } if resp != nil { if resp.IsError() { return fmt.Errorf("Error on resp: %#v", *resp) } } client, err = rabbithole.NewClient(uri, d.Username, d.Password) if err != nil { t.Fatal(err) } _, err = client.ListVhosts() if err == nil { t.Fatalf("expected to fail listing vhosts: %s", err) } return nil }, } }
func testAccStepDropTable(t *testing.T, b logical.Backend, s logical.Storage, name string, connURL string) logicaltest.TestStep { return logicaltest.TestStep{ Operation: logical.ReadOperation, Path: path.Join("creds", name), Check: func(resp *logical.Response) error { var d struct { Username string `mapstructure:"username"` Password string `mapstructure:"password"` } if err := mapstructure.Decode(resp.Data, &d); err != nil { return err } log.Printf("[TRACE] Generated credentials: %v", d) conn, err := pq.ParseURL(connURL) if err != nil { t.Fatal(err) } conn += " timezone=utc" db, err := sql.Open("postgres", conn) if err != nil { t.Fatal(err) } _, err = db.Exec("DROP TABLE test;") if err != nil { t.Fatal(err) } resp, err = b.HandleRequest(&logical.Request{ Operation: logical.RevokeOperation, Storage: s, Secret: &logical.Secret{ InternalData: map[string]interface{}{ "secret_type": "creds", "username": d.Username, }, }, }) if err != nil { return err } if resp != nil { if resp.IsError() { return fmt.Errorf("Error on resp: %#v", *resp) } } return nil }, } }
func TestPathStruct(t *testing.T) { p := &PathStruct{ Name: "foo", Path: "bar", Schema: map[string]*FieldSchema{ "value": &FieldSchema{Type: TypeString}, }, Read: true, } storage := new(logical.InmemStorage) var b logical.Backend = &Backend{Paths: p.Paths()} // Write via HTTP _, err := b.HandleRequest(&logical.Request{ Operation: logical.WriteOperation, Path: "bar", Data: map[string]interface{}{ "value": "baz", }, Storage: storage, }) if err != nil { t.Fatalf("bad: %#v", err) } // Read via HTTP resp, err := b.HandleRequest(&logical.Request{ Operation: logical.ReadOperation, Path: "bar", Storage: storage, }) if err != nil { t.Fatalf("bad: %#v", err) } if resp.Data["value"] != "baz" { t.Fatalf("bad: %#v", resp) } // Read via API v, err := p.Get(storage) if err != nil { t.Fatalf("bad: %#v", err) } if v["value"] != "baz" { t.Fatalf("bad: %#v", v) } }
func prepareTestContainer(t *testing.T, s logical.Storage, b logical.Backend) (cid dockertest.ContainerID, retURI string) { if os.Getenv("MONGODB_URI") != "" { return "", os.Getenv("MONGODB_URI") } // Without this the checks for whether the container has started seem to // never actually pass. There's really no reason to expose the test // containers, so don't. dockertest.BindDockerToLocalhost = "yep" testImagePull.Do(func() { dockertest.Pull(dockertest.MongoDBImageName) }) cid, connErr := dockertest.ConnectToMongoDB(60, 500*time.Millisecond, func(connURI string) bool { connURI = "mongodb://" + connURI // This will cause a validation to run resp, err := b.HandleRequest(&logical.Request{ Storage: s, Operation: logical.UpdateOperation, Path: "config/connection", Data: map[string]interface{}{ "uri": connURI, }, }) if err != nil || (resp != nil && resp.IsError()) { // It's likely not up and running yet, so return false and try again return false } if resp == nil { t.Fatal("expected warning") } retURI = connURI return true }) if connErr != nil { t.Fatalf("could not connect to database: %v", connErr) } return }
func TestPathMap_Salted(t *testing.T) { storage := new(logical.InmemStorage) salt, err := salt.NewSalt(storage, &salt.Config{ HashFunc: salt.SHA1Hash, }) if err != nil { t.Fatalf("err: %v", err) } p := &PathMap{Name: "foo", Salt: salt} var b logical.Backend = &Backend{Paths: p.Paths()} // Write via HTTP _, err = b.HandleRequest(&logical.Request{ Operation: logical.WriteOperation, Path: "map/foo/a", Data: map[string]interface{}{ "value": "bar", }, Storage: storage, }) if err != nil { t.Fatalf("bad: %#v", err) } // Non-salted version should not be there out, err := storage.Get("struct/map/foo/a") if err != nil { t.Fatalf("err: %v", err) } if out != nil { t.Fatalf("non-salted key found") } // Ensure the path is salted expect := salt.SaltID("a") out, err = storage.Get("struct/map/foo/" + expect) if err != nil { t.Fatalf("err: %v", err) } if out == nil { t.Fatalf("missing salted key") } // Read via HTTP resp, err := b.HandleRequest(&logical.Request{ Operation: logical.ReadOperation, Path: "map/foo/a", Storage: storage, }) if err != nil { t.Fatalf("bad: %#v", err) } if resp.Data["value"] != "bar" { t.Fatalf("bad: %#v", resp) } // Read via API v, err := p.Get(storage, "a") if err != nil { t.Fatalf("bad: %#v", err) } if v["value"] != "bar" { t.Fatalf("bad: %#v", v) } // Read via API with other casing v, err = p.Get(storage, "A") if err != nil { t.Fatalf("bad: %#v", err) } if v["value"] != "bar" { t.Fatalf("bad: %#v", v) } // Verify List keys, err := p.List(storage, "") if err != nil { t.Fatalf("bad: %#v", err) } if len(keys) != 1 || keys[0] != expect { t.Fatalf("bad: %#v", keys) } // Delete via HTTP resp, err = b.HandleRequest(&logical.Request{ Operation: logical.DeleteOperation, Path: "map/foo/a", Storage: storage, }) if err != nil { t.Fatalf("bad: %#v", err) } if resp != nil { t.Fatalf("bad: %#v", resp) } // Re-read via HTTP resp, err = b.HandleRequest(&logical.Request{ Operation: logical.ReadOperation, Path: "map/foo/a", Storage: storage, }) if err != nil { t.Fatalf("bad: %#v", err) } if _, ok := resp.Data["value"]; ok { t.Fatalf("bad: %#v", resp) } // Re-read via API v, err = p.Get(storage, "a") if err != nil { t.Fatalf("bad: %#v", err) } if v != nil { t.Fatalf("bad: %#v", v) } }
func testAccStepReadCreds(t *testing.T, b logical.Backend, s logical.Storage, name string, connURL string) logicaltest.TestStep { return logicaltest.TestStep{ Operation: logical.ReadOperation, Path: "creds/" + name, Check: func(resp *logical.Response) error { var d struct { Username string `mapstructure:"username"` Password string `mapstructure:"password"` } if err := mapstructure.Decode(resp.Data, &d); err != nil { return err } log.Printf("[WARN] Generated credentials: %v", d) conn, err := pq.ParseURL(connURL) if err != nil { t.Fatal(err) } conn += " timezone=utc" db, err := sql.Open("postgres", conn) if err != nil { t.Fatal(err) } returnedRows := func() int { stmt, err := db.Prepare("SELECT DISTINCT schemaname FROM pg_tables WHERE has_table_privilege($1, 'information_schema.role_column_grants', 'select');") if err != nil { return -1 } defer stmt.Close() rows, err := stmt.Query(d.Username) if err != nil { return -1 } defer rows.Close() i := 0 for rows.Next() { i++ } return i } userRows := returnedRows() if userRows != 2 { t.Fatalf("did not get expected number of rows, got %d", userRows) } resp, err = b.HandleRequest(&logical.Request{ Operation: logical.RevokeOperation, Storage: s, Secret: &logical.Secret{ InternalData: map[string]interface{}{ "secret_type": "creds", "username": d.Username, }, }, }) if err != nil { return err } if resp != nil { if resp.IsError() { return fmt.Errorf("Error on resp: %#v", *resp) } } userRows = returnedRows() // User shouldn't exist so returnedRows() should encounter an error and exit with -1 if userRows != -1 { t.Fatalf("did not get expected number of rows, got %d", userRows) } return nil }, } }
func testAccStepReadCreds(t *testing.T, b logical.Backend, name string) logicaltest.TestStep { return logicaltest.TestStep{ Operation: logical.ReadOperation, Path: "creds/" + name, Check: func(resp *logical.Response) error { var d struct { Username string `mapstructure:"username"` Password string `mapstructure:"password"` } if err := mapstructure.Decode(resp.Data, &d); err != nil { return err } log.Printf("[WARN] Generated credentials: %v", d) conn, err := pq.ParseURL(os.Getenv("PG_URL")) if err != nil { t.Fatal(err) } conn += " timezone=utc" db, err := sql.Open("postgres", conn) if err != nil { t.Fatal(err) } returnedRows := func() int { stmt, err := db.Prepare(fmt.Sprintf( "SELECT DISTINCT table_schema FROM information_schema.role_column_grants WHERE grantee='%s';", d.Username)) if err != nil { return -1 } defer stmt.Close() rows, err := stmt.Query() if err != nil { return -1 } defer rows.Close() i := 0 for rows.Next() { i++ } return i } userRows := returnedRows() if userRows != 1 { t.Fatalf("did not get expected number of rows, got %d", userRows) } resp, err = b.HandleRequest(&logical.Request{ Operation: logical.RevokeOperation, Secret: &logical.Secret{ InternalData: map[string]interface{}{ "secret_type": "creds", "username": d.Username, }, }, }) if err != nil { return err } if resp != nil { if resp.IsError() { return fmt.Errorf("Error on resp: %#v", *resp) } } userRows = returnedRows() if userRows != 0 { t.Fatalf("did not get expected number of rows, got %d", userRows) } return nil }, } }