diff --git a/logical/request.go b/logical/request.go index b4492eb60..92a69903b 100644 --- a/logical/request.go +++ b/logical/request.go @@ -47,6 +47,11 @@ type Request struct { // dynamic secrets with the source entity. This is not a sensitive // name, but is useful for operators. DisplayName string + + // MountPoint is provided so that a logical backend can generate + // paths relative to itself. The `Path` is effectively the client + // request path with the MountPoint trimmed off. + MountPoint string } // Get returns a data field and guards for nil Data diff --git a/vault/core_test.go b/vault/core_test.go index 8ce441b20..112e9ce11 100644 --- a/vault/core_test.go +++ b/vault/core_test.go @@ -1472,3 +1472,42 @@ func TestCore_EnableDisableCred_WithLease(t *testing.T) { t.Fatalf("err: %v %#v", err, resp) } } + +func TestCore_HandleRequest_MountPoint(t *testing.T) { + noop := &NoopBackend{ + Response: &logical.Response{}, + } + c, _, root := TestCoreUnsealed(t) + c.logicalBackends["noop"] = func(map[string]string) (logical.Backend, error) { + return noop, nil + } + + // Enable the logical backend + req := logical.TestRequest(t, logical.WriteOperation, "sys/mounts/foo") + req.Data["type"] = "noop" + req.Data["description"] = "foo" + req.ClientToken = root + _, err := c.HandleRequest(req) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Attempt to request + req = &logical.Request{ + Operation: logical.ReadOperation, + Path: "foo/test", + Connection: &logical.Connection{}, + } + req.ClientToken = root + if _, err := c.HandleRequest(req); err != nil { + t.Fatalf("err: %v", err) + } + + // Verify Path and MountPoint + if noop.Requests[0].Path != "test" { + t.Fatalf("bad: %#v", noop.Requests) + } + if noop.Requests[0].MountPoint != "foo/" { + t.Fatalf("bad: %#v", noop.Requests) + } +} diff --git a/vault/router.go b/vault/router.go index 9d183a3a0..653d5aa5d 100644 --- a/vault/router.go +++ b/vault/router.go @@ -178,6 +178,7 @@ func (r *Router) Route(req *logical.Request) (*logical.Response, error) { // Adjust the path to exclude the routing prefix original := req.Path req.Path = strings.TrimPrefix(req.Path, mount) + req.MountPoint = mount if req.Path == "/" { req.Path = "" } @@ -200,6 +201,7 @@ func (r *Router) Route(req *logical.Request) (*logical.Response, error) { // Reset the request before returning defer func() { req.Path = original + req.MountPoint = "" req.Connection = originalConn req.Storage = nil req.ClientToken = clientToken