// Mount is used to mount a new backend to the mount table. func (c *Core) mount(me *MountEntry) error { // Ensure we end the path in a slash if !strings.HasSuffix(me.Path, "/") { me.Path += "/" } // Prevent protected paths from being mounted for _, p := range protectedMounts { if strings.HasPrefix(me.Path, p) { return logical.CodedError(403, fmt.Sprintf("cannot mount '%s'", me.Path)) } } // Do not allow more than one instance of a singleton mount for _, p := range singletonMounts { if me.Type == p { return logical.CodedError(403, fmt.Sprintf("Cannot mount more than one instance of '%s'", me.Type)) } } // Verify there is no conflicting mount if match := c.router.MatchingMount(me.Path); match != "" { return logical.CodedError(409, fmt.Sprintf("existing mount at %s", match)) } // Generate a new UUID and view meUUID, err := uuid.GenerateUUID() if err != nil { return err } me.UUID = meUUID view := NewBarrierView(c.barrier, backendBarrierPrefix+me.UUID+"/") backend, err := c.newLogicalBackend(me.Type, c.mountEntrySysView(me), view, nil) if err != nil { return err } // Update the mount table c.mountsLock.Lock() newTable := c.mounts.shallowClone() newTable.Entries = append(newTable.Entries, me) if err := c.persistMounts(newTable); err != nil { c.mountsLock.Unlock() return logical.CodedError(500, "failed to update mount table") } c.mounts = newTable c.mountsLock.Unlock() // Mount the backend if err := c.router.Mount(backend, me.Path, me, view); err != nil { return err } if c.logger.IsInfo() { c.logger.Info("core: successful mount", "path", me.Path, "type", me.Type) } return nil }
func TestHandler_error(t *testing.T) { w := httptest.NewRecorder() respondError(w, 500, errors.New("Test Error")) if w.Code != 500 { t.Fatalf("expected 500, got %d", w.Code) } // The code inside of the error should override // the argument to respondError w2 := httptest.NewRecorder() e := logical.CodedError(403, "error text") respondError(w2, 500, e) if w2.Code != 403 { t.Fatalf("expected 403, got %d", w2.Code) } // vault.ErrSealed is a special case w3 := httptest.NewRecorder() respondError(w3, 400, vault.ErrSealed) if w3.Code != 503 { t.Fatalf("expected 503, got %d", w3.Code) } }
// enableCredential is used to enable a new credential backend func (c *Core) enableCredential(entry *MountEntry) error { // Ensure we end the path in a slash if !strings.HasSuffix(entry.Path, "/") { entry.Path += "/" } // Ensure there is a name if entry.Path == "/" { return fmt.Errorf("backend path must be specified") } c.authLock.Lock() defer c.authLock.Unlock() // Look for matching name for _, ent := range c.auth.Entries { switch { // Existing is oauth/github/ new is oauth/ or // existing is oauth/ and new is oauth/github/ case strings.HasPrefix(ent.Path, entry.Path): fallthrough case strings.HasPrefix(entry.Path, ent.Path): return logical.CodedError(409, "path is already in use") } } // Ensure the token backend is a singleton if entry.Type == "token" { return fmt.Errorf("token credential backend cannot be instantiated") } // Generate a new UUID and view entry.UUID = uuid.GenerateUUID() view := NewBarrierView(c.barrier, credentialBarrierPrefix+entry.UUID+"/") // Create the new backend backend, err := c.newCredentialBackend(entry.Type, c.mountEntrySysView(entry), view, nil) if err != nil { return err } // Update the auth table newTable := c.auth.ShallowClone() newTable.Entries = append(newTable.Entries, entry) if err := c.persistAuth(newTable); err != nil { return errors.New("failed to update auth table") } c.auth = newTable // Mount the backend path := credentialRoutePrefix + entry.Path if err := c.router.Mount(backend, path, entry, view); err != nil { return err } c.logger.Printf("[INFO] core: enabled credential backend '%s' type: %s", entry.Path, entry.Type) return nil }
// Mount is used to mount a new backend to the mount table. func (c *Core) mount(me *MountEntry) error { c.mounts.Lock() defer c.mounts.Unlock() // Ensure we end the path in a slash if !strings.HasSuffix(me.Path, "/") { me.Path += "/" } // Prevent protected paths from being mounted for _, p := range protectedMounts { if strings.HasPrefix(me.Path, p) { return logical.CodedError(403, fmt.Sprintf("cannot mount '%s'", me.Path)) } } // Verify there is no conflicting mount if match := c.router.MatchingMount(me.Path); match != "" { return logical.CodedError(409, fmt.Sprintf("existing mount at %s", match)) } // Generate a new UUID and view me.UUID = uuid.GenerateUUID() view := NewBarrierView(c.barrier, backendBarrierPrefix+me.UUID+"/") // Create the new backend backend, err := c.newLogicalBackend(me.Type, view, nil) if err != nil { return err } // Update the mount table newTable := c.mounts.Clone() newTable.Entries = append(newTable.Entries, me) if err := c.persistMounts(newTable); err != nil { return errors.New("failed to update mount table") } c.mounts = newTable // Mount the backend if err := c.router.Mount(backend, me.Path, me.UUID, view); err != nil { return err } c.logger.Printf("[INFO] core: mounted '%s' type: %s", me.Path, me.Type) return nil }
// taintMountEntry is used to mark an entry in the mount table as tainted func (c *Core) taintMountEntry(path string) error { // As modifying the taint of an entry affects shallow clones, // we simply use the original c.mounts.SetTaint(path, true) // Update the mount table if err := c.persistMounts(c.mounts); err != nil { return logical.CodedError(500, "failed to update mount table") } return nil }
// removeMountEntry is used to remove an entry from the mount table func (c *Core) removeMountEntry(path string) error { // Remove the entry from the mount table newTable := c.mounts.ShallowClone() newTable.Remove(path) // Update the mount table if err := c.persistMounts(newTable); err != nil { return logical.CodedError(500, "failed to update mount table") } c.mounts = newTable return nil }
// Remount is used to remount a path at a new mount point. func (c *Core) remount(src, dst string) error { // Ensure we end the path in a slash if !strings.HasSuffix(src, "/") { src += "/" } if !strings.HasSuffix(dst, "/") { dst += "/" } // Prevent protected paths from being remounted for _, p := range protectedMounts { if strings.HasPrefix(src, p) { return fmt.Errorf("cannot remount '%s'", src) } } // Verify exact match of the route match := c.router.MatchingMount(src) if match == "" || src != match { return fmt.Errorf("no matching mount at '%s'", src) } if match := c.router.MatchingMount(dst); match != "" { return fmt.Errorf("existing mount at '%s'", match) } // Mark the entry as tainted if err := c.taintMountEntry(src); err != nil { return err } // Taint the router path to prevent routing if err := c.router.Taint(src); err != nil { return err } // Invoke the rollback manager a final time if err := c.rollback.Rollback(src); err != nil { return err } // Revoke all the dynamic keys if err := c.expiration.RevokePrefix(src); err != nil { return err } c.mountsLock.Lock() var ent *MountEntry for _, ent = range c.mounts.Entries { if ent.Path == src { ent.Path = dst ent.Tainted = false break } } // Update the mount table if err := c.persistMounts(c.mounts); err != nil { ent.Path = src ent.Tainted = true c.mountsLock.Unlock() return logical.CodedError(500, "failed to update mount table") } c.mountsLock.Unlock() // Remount the backend if err := c.router.Remount(src, dst); err != nil { return err } // Un-taint the path if err := c.router.Untaint(dst); err != nil { return err } if c.logger.IsInfo() { c.logger.Info("core: successful remount", "old_path", src, "new_path", dst) } return nil }