Cleaning up logical and auth unmount functions (#2994)

This commit is contained in:
Chris Hoffman 2017-07-13 10:57:14 -07:00 committed by GitHub
parent 11725705d1
commit d481e65c5a
5 changed files with 67 additions and 77 deletions

View File

@ -131,7 +131,7 @@ func (c *Core) enableCredential(entry *MountEntry) error {
// disableCredential is used to disable an existing credential backend; the // disableCredential is used to disable an existing credential backend; the
// boolean indicates if it existed // boolean indicates if it existed
func (c *Core) disableCredential(path string) (bool, error) { func (c *Core) disableCredential(path string) error {
// Ensure we end the path in a slash // Ensure we end the path in a slash
if !strings.HasSuffix(path, "/") { if !strings.HasSuffix(path, "/") {
path += "/" path += "/"
@ -139,29 +139,29 @@ func (c *Core) disableCredential(path string) (bool, error) {
// Ensure the token backend is not affected // Ensure the token backend is not affected
if path == "token/" { if path == "token/" {
return true, fmt.Errorf("token credential backend cannot be disabled") return fmt.Errorf("token credential backend cannot be disabled")
} }
// Store the view for this backend // Store the view for this backend
fullPath := credentialRoutePrefix + path fullPath := credentialRoutePrefix + path
view := c.router.MatchingStorageView(fullPath) view := c.router.MatchingStorageView(fullPath)
if view == nil { if view == nil {
return false, fmt.Errorf("no matching backend %s", fullPath) return fmt.Errorf("no matching backend %s", fullPath)
} }
// Mark the entry as tainted // Mark the entry as tainted
if err := c.taintCredEntry(path); err != nil { if err := c.taintCredEntry(path); err != nil {
return true, err return err
} }
// Taint the router path to prevent routing // Taint the router path to prevent routing
if err := c.router.Taint(fullPath); err != nil { if err := c.router.Taint(fullPath); err != nil {
return true, err return err
} }
// Revoke credentials from this path // Revoke credentials from this path
if err := c.expiration.RevokePrefix(fullPath); err != nil { if err := c.expiration.RevokePrefix(fullPath); err != nil {
return true, err return err
} }
// Call cleanup function if it exists // Call cleanup function if it exists
@ -172,24 +172,24 @@ func (c *Core) disableCredential(path string) (bool, error) {
// Unmount the backend // Unmount the backend
if err := c.router.Unmount(fullPath); err != nil { if err := c.router.Unmount(fullPath); err != nil {
return true, err return err
} }
// Clear the data in the view // Clear the data in the view
if view != nil { if view != nil {
if err := logical.ClearView(view); err != nil { if err := logical.ClearView(view); err != nil {
return true, err return err
} }
} }
// Remove the mount table entry // Remove the mount table entry
if err := c.removeCredEntry(path); err != nil { if err := c.removeCredEntry(path); err != nil {
return true, err return err
} }
if c.logger.IsInfo() { if c.logger.IsInfo() {
c.logger.Info("core: disabled credential backend", "path", path) c.logger.Info("core: disabled credential backend", "path", path)
} }
return true, nil return nil
} }
// removeCredEntry is used to remove an entry in the auth table // removeCredEntry is used to remove an entry in the auth table

View File

@ -217,9 +217,9 @@ func TestCore_DisableCredential(t *testing.T) {
return &NoopBackend{}, nil return &NoopBackend{}, nil
} }
existed, err := c.disableCredential("foo") err := c.disableCredential("foo")
if existed || (err != nil && !strings.HasPrefix(err.Error(), "no matching backend")) { if err != nil && !strings.HasPrefix(err.Error(), "no matching backend") {
t.Fatalf("existed: %v; err: %v", existed, err) t.Fatalf("err: %v", err)
} }
me := &MountEntry{ me := &MountEntry{
@ -232,9 +232,9 @@ func TestCore_DisableCredential(t *testing.T) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
existed, err = c.disableCredential("foo") err = c.disableCredential("foo")
if !existed || err != nil { if err != nil {
t.Fatalf("existed: %v; err: %v", existed, err) t.Fatalf("err: %v", err)
} }
match := c.router.MatchingMount("auth/foo/bar") match := c.router.MatchingMount("auth/foo/bar")
@ -268,9 +268,9 @@ func TestCore_DisableCredential(t *testing.T) {
func TestCore_DisableCredential_Protected(t *testing.T) { func TestCore_DisableCredential_Protected(t *testing.T) {
c, _, _ := TestCoreUnsealed(t) c, _, _ := TestCoreUnsealed(t)
existed, err := c.disableCredential("token") err := c.disableCredential("token")
if !existed || err.Error() != "token credential backend cannot be disabled" { if err.Error() != "token credential backend cannot be disabled" {
t.Fatalf("existed: %v; err: %v", existed, err) t.Fatalf("err: %v", err)
} }
} }
@ -324,9 +324,9 @@ func TestCore_DisableCredential_Cleanup(t *testing.T) {
} }
// Disable should cleanup // Disable should cleanup
existed, err := c.disableCredential("foo") err = c.disableCredential("foo")
if !existed || err != nil { if err != nil {
t.Fatalf("existed: %v; err: %v", existed, err) t.Fatalf("err: %v", err)
} }
// Token should be revoked // Token should be revoked

View File

@ -1293,25 +1293,25 @@ func handleError(
// handleUnmount is used to unmount a path // handleUnmount is used to unmount a path
func (b *SystemBackend) handleUnmount( func (b *SystemBackend) handleUnmount(
req *logical.Request, data *framework.FieldData) (*logical.Response, error) { req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
b.Core.clusterParamsLock.RLock() path := data.Get("path").(string)
repState := b.Core.replicationState path = sanitizeMountPath(path)
b.Core.clusterParamsLock.RUnlock()
suffix := strings.TrimPrefix(req.Path, "mounts/") repState := b.Core.ReplicationState()
if len(suffix) == 0 { entry := b.Core.router.MatchingMountEntry(path)
return logical.ErrorResponse("path cannot be blank"), logical.ErrInvalidRequest
}
suffix = sanitizeMountPath(suffix)
entry := b.Core.router.MatchingMountEntry(suffix)
if entry != nil && !entry.Local && repState == consts.ReplicationSecondary { if entry != nil && !entry.Local && repState == consts.ReplicationSecondary {
return logical.ErrorResponse("cannot unmount a non-local mount on a replication secondary"), nil return logical.ErrorResponse("cannot unmount a non-local mount on a replication secondary"), nil
} }
// We return success when the mount does not exists to not expose if the
// mount existed or not
match := b.Core.router.MatchingMount(path)
if match == "" || path != match {
return nil, nil
}
// Attempt unmount // Attempt unmount
if existed, err := b.Core.unmount(suffix); existed && err != nil { if err := b.Core.unmount(path); err != nil {
b.Backend.Logger().Error("sys: unmount failed", "path", suffix, "error", err) b.Backend.Logger().Error("sys: unmount failed", "path", path, "error", err)
return handleError(err) return handleError(err)
} }
@ -1714,16 +1714,26 @@ func (b *SystemBackend) handleEnableAuth(
// handleDisableAuth is used to disable a credential backend // handleDisableAuth is used to disable a credential backend
func (b *SystemBackend) handleDisableAuth( func (b *SystemBackend) handleDisableAuth(
req *logical.Request, data *framework.FieldData) (*logical.Response, error) { req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
suffix := strings.TrimPrefix(req.Path, "auth/") path := data.Get("path").(string)
if len(suffix) == 0 { path = sanitizeMountPath(path)
return logical.ErrorResponse("path cannot be blank"), logical.ErrInvalidRequest fullPath := credentialRoutePrefix + path
repState := b.Core.ReplicationState()
entry := b.Core.router.MatchingMountEntry(fullPath)
if entry != nil && !entry.Local && repState == consts.ReplicationSecondary {
return logical.ErrorResponse("cannot unmount a non-local mount on a replication secondary"), nil
} }
suffix = sanitizeMountPath(suffix) // We return success when the mount does not exists to not expose if the
// mount existed or not
match := b.Core.router.MatchingMount(fullPath)
if match == "" || fullPath != match {
return nil, nil
}
// Attempt disable // Attempt disable
if existed, err := b.Core.disableCredential(suffix); existed && err != nil { if err := b.Core.disableCredential(path); err != nil {
b.Backend.Logger().Error("sys: disable auth mount failed", "path", suffix, "error", err) b.Backend.Logger().Error("sys: disable auth mount failed", "path", path, "error", err)
return handleError(err) return handleError(err)
} }
return nil, nil return nil, nil

View File

@ -169,26 +169,6 @@ type MountConfig struct {
ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"` // Override for global default ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"` // Override for global default
} }
// Returns a deep copy of the mount entry
func (e *MountEntry) Clone() *MountEntry {
optClone := make(map[string]string)
for k, v := range e.Options {
optClone[k] = v
}
return &MountEntry{
Table: e.Table,
Path: e.Path,
Type: e.Type,
Description: e.Description,
UUID: e.UUID,
Accessor: e.Accessor,
Config: e.Config,
Options: optClone,
Local: e.Local,
Tainted: e.Tainted,
}
}
// Mount is used to mount a new backend to the mount table. // Mount is used to mount a new backend to the mount table.
func (c *Core) mount(entry *MountEntry) error { func (c *Core) mount(entry *MountEntry) error {
// Ensure we end the path in a slash // Ensure we end the path in a slash
@ -271,7 +251,7 @@ func (c *Core) mount(entry *MountEntry) error {
// Unmount is used to unmount a path. The boolean indicates whether the mount // Unmount is used to unmount a path. The boolean indicates whether the mount
// was found. // was found.
func (c *Core) unmount(path string) (bool, error) { func (c *Core) unmount(path string) error {
// Ensure we end the path in a slash // Ensure we end the path in a slash
if !strings.HasSuffix(path, "/") { if !strings.HasSuffix(path, "/") {
path += "/" path += "/"
@ -280,14 +260,14 @@ func (c *Core) unmount(path string) (bool, error) {
// Prevent protected paths from being unmounted // Prevent protected paths from being unmounted
for _, p := range protectedMounts { for _, p := range protectedMounts {
if strings.HasPrefix(path, p) { if strings.HasPrefix(path, p) {
return true, fmt.Errorf("cannot unmount '%s'", path) return fmt.Errorf("cannot unmount '%s'", path)
} }
} }
// Verify exact match of the route // Verify exact match of the route
match := c.router.MatchingMount(path) match := c.router.MatchingMount(path)
if match == "" || path != match { if match == "" || path != match {
return false, fmt.Errorf("no matching mount") return fmt.Errorf("no matching mount")
} }
// Get the view for this backend // Get the view for this backend
@ -295,23 +275,23 @@ func (c *Core) unmount(path string) (bool, error) {
// Mark the entry as tainted // Mark the entry as tainted
if err := c.taintMountEntry(path); err != nil { if err := c.taintMountEntry(path); err != nil {
return true, err return err
} }
// Taint the router path to prevent routing. Note that in-flight requests // Taint the router path to prevent routing. Note that in-flight requests
// are uncertain, right now. // are uncertain, right now.
if err := c.router.Taint(path); err != nil { if err := c.router.Taint(path); err != nil {
return true, err return err
} }
// Invoke the rollback manager a final time // Invoke the rollback manager a final time
if err := c.rollback.Rollback(path); err != nil { if err := c.rollback.Rollback(path); err != nil {
return true, err return err
} }
// Revoke all the dynamic keys // Revoke all the dynamic keys
if err := c.expiration.RevokePrefix(path); err != nil { if err := c.expiration.RevokePrefix(path); err != nil {
return true, err return err
} }
// Call cleanup function if it exists // Call cleanup function if it exists
@ -322,22 +302,22 @@ func (c *Core) unmount(path string) (bool, error) {
// Unmount the backend entirely // Unmount the backend entirely
if err := c.router.Unmount(path); err != nil { if err := c.router.Unmount(path); err != nil {
return true, err return err
} }
// Clear the data in the view // Clear the data in the view
if err := logical.ClearView(view); err != nil { if err := logical.ClearView(view); err != nil {
return true, err return err
} }
// Remove the mount table entry // Remove the mount table entry
if err := c.removeMountEntry(path); err != nil { if err := c.removeMountEntry(path); err != nil {
return true, err return err
} }
if c.logger.IsInfo() { if c.logger.IsInfo() {
c.logger.Info("core: successfully unmounted", "path", path) c.logger.Info("core: successfully unmounted", "path", path)
} }
return true, nil return nil
} }
// removeMountEntry is used to remove an entry from the mount table // removeMountEntry is used to remove an entry from the mount table

View File

@ -181,9 +181,9 @@ func TestCore_Mount_Local(t *testing.T) {
func TestCore_Unmount(t *testing.T) { func TestCore_Unmount(t *testing.T) {
c, keys, _ := TestCoreUnsealed(t) c, keys, _ := TestCoreUnsealed(t)
existed, err := c.unmount("secret") err := c.unmount("secret")
if !existed || err != nil { if err != nil {
t.Fatalf("existed: %v; err: %v", existed, err) t.Fatalf("err: %v", err)
} }
match := c.router.MatchingMount("secret/foo") match := c.router.MatchingMount("secret/foo")
@ -272,8 +272,8 @@ func TestCore_Unmount_Cleanup(t *testing.T) {
} }
// Unmount, this should cleanup // Unmount, this should cleanup
if existed, err := c.unmount("test/"); !existed || err != nil { if err := c.unmount("test/"); err != nil {
t.Fatalf("existed: %v; err: %v", existed, err) t.Fatalf("err: %v", err)
} }
// Rollback should be invoked // Rollback should be invoked