vault: implement the sys/auth* endpoints
This commit is contained in:
parent
86a6062ba2
commit
82e13e3c41
|
@ -14,6 +14,7 @@ func NewSystemBackend(core *Core) logical.Backend {
|
|||
return &framework.Backend{
|
||||
PathsRoot: []string{
|
||||
"mounts/*",
|
||||
"auth/*",
|
||||
"remount",
|
||||
"revoke-prefix/*",
|
||||
},
|
||||
|
@ -137,6 +138,44 @@ func NewSystemBackend(core *Core) logical.Backend {
|
|||
HelpSynopsis: strings.TrimSpace(sysHelp["revoke-prefix"][0]),
|
||||
HelpDescription: strings.TrimSpace(sysHelp["revoke-prefix"][1]),
|
||||
},
|
||||
|
||||
&framework.Path{
|
||||
Pattern: "auth$",
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
logical.ReadOperation: b.handleAuthTable,
|
||||
},
|
||||
|
||||
HelpSynopsis: strings.TrimSpace(sysHelp["auth-table"][0]),
|
||||
HelpDescription: strings.TrimSpace(sysHelp["auth-table"][1]),
|
||||
},
|
||||
|
||||
&framework.Path{
|
||||
Pattern: "auth/(?P<path>.+)",
|
||||
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"path": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: strings.TrimSpace(sysHelp["auth_path"][0]),
|
||||
},
|
||||
"type": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: strings.TrimSpace(sysHelp["auth_type"][0]),
|
||||
},
|
||||
"description": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: strings.TrimSpace(sysHelp["auth_desc"][0]),
|
||||
},
|
||||
},
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
logical.WriteOperation: b.handleEnableAuth,
|
||||
logical.DeleteOperation: b.handleDisableAuth,
|
||||
},
|
||||
|
||||
HelpSynopsis: strings.TrimSpace(sysHelp["auth"][0]),
|
||||
HelpDescription: strings.TrimSpace(sysHelp["auth"][1]),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -281,6 +320,69 @@ func (b *SystemBackend) handleRevokePrefix(
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// handleAuthTable handles the "auth" endpoint to provide the auth table
|
||||
func (b *SystemBackend) handleAuthTable(
|
||||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
b.Core.auth.Lock()
|
||||
defer b.Core.auth.Unlock()
|
||||
|
||||
resp := &logical.Response{
|
||||
Data: make(map[string]interface{}),
|
||||
}
|
||||
for _, entry := range b.Core.auth.Entries {
|
||||
info := map[string]string{
|
||||
"type": entry.Type,
|
||||
"description": entry.Description,
|
||||
}
|
||||
resp.Data[entry.Path] = info
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// handleEnableAuth is used to enable a new credential backend
|
||||
func (b *SystemBackend) handleEnableAuth(
|
||||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
// Get all the options
|
||||
path := data.Get("path").(string)
|
||||
logicalType := data.Get("type").(string)
|
||||
description := data.Get("description").(string)
|
||||
|
||||
if logicalType == "" {
|
||||
return logical.ErrorResponse(
|
||||
"backend type must be specified as a string"),
|
||||
logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
// Create the mount entry
|
||||
me := &MountEntry{
|
||||
Path: path,
|
||||
Type: logicalType,
|
||||
Description: description,
|
||||
}
|
||||
|
||||
// Attempt enabling
|
||||
if err := b.Core.enableCredential(me); err != nil {
|
||||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// handleDisableAuth is used to disable a credential backend
|
||||
func (b *SystemBackend) handleDisableAuth(
|
||||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
suffix := strings.TrimPrefix(req.Path, "auth/")
|
||||
if len(suffix) == 0 {
|
||||
return logical.ErrorResponse("path cannot be blank"), logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
// Attempt disable
|
||||
if err := b.Core.disableCredential(suffix); err != nil {
|
||||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// sysHelp is all the help text for the sys backend.
|
||||
var sysHelp = map[string][2]string{
|
||||
"mounts": {
|
||||
|
@ -379,4 +481,36 @@ all matching leases.
|
|||
`The path to revoke keys under. Example: "prod/aws/ops"`,
|
||||
"",
|
||||
},
|
||||
|
||||
"auth-table": {
|
||||
"List the currently enabled credential backends.",
|
||||
`
|
||||
List the currently enabled credential backends: the name, the type of the backend,
|
||||
and a user friendly description of the purpose for the credential backend.
|
||||
`,
|
||||
},
|
||||
|
||||
"auth": {
|
||||
`Enable a new credential backend with a name.`,
|
||||
`
|
||||
Enable a credential mechanism at a new path. A backend can be mounted multiple times at
|
||||
multiple paths in order to configure multiple separately configured backends.
|
||||
Example: you might have an OAuth backend for GitHub, and one for Google Apps.
|
||||
`,
|
||||
},
|
||||
|
||||
"auth_path": {
|
||||
`The path to mount to. Cannot be delimited. Example: "user"`,
|
||||
"",
|
||||
},
|
||||
|
||||
"auth_type": {
|
||||
`The type of the backend. Example: "userpass"`,
|
||||
"",
|
||||
},
|
||||
|
||||
"auth_desc": {
|
||||
`User-friendly description for this crential backend.`,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -4,12 +4,14 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/credential"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
func TestSystemBackend_RootPaths(t *testing.T) {
|
||||
expected := []string{
|
||||
"mounts/*",
|
||||
"auth/*",
|
||||
"remount",
|
||||
"revoke-prefix/*",
|
||||
}
|
||||
|
@ -305,6 +307,91 @@ func TestSystemBackend_revokePrefix(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSystemBackend_authTable(t *testing.T) {
|
||||
b := testSystemBackend(t)
|
||||
req := logical.TestRequest(t, logical.ReadOperation, "auth")
|
||||
resp, err := b.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
exp := map[string]interface{}{
|
||||
"token": map[string]string{
|
||||
"type": "token",
|
||||
"description": "token based credentials",
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(resp.Data, exp) {
|
||||
t.Fatalf("got: %#v expect: %#v", resp.Data, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemBackend_enableAuth(t *testing.T) {
|
||||
c, b := testCoreSystemBackend(t)
|
||||
c.credentialBackends["noop"] = func(map[string]string) (credential.Backend, error) {
|
||||
return &NoopCred{}, nil
|
||||
}
|
||||
|
||||
req := logical.TestRequest(t, logical.WriteOperation, "auth/foo")
|
||||
req.Data["type"] = "noop"
|
||||
|
||||
resp, err := b.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if resp != nil {
|
||||
t.Fatalf("bad: %v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemBackend_enableAuth_invalid(t *testing.T) {
|
||||
b := testSystemBackend(t)
|
||||
req := logical.TestRequest(t, logical.WriteOperation, "auth/foo")
|
||||
req.Data["type"] = "nope"
|
||||
resp, err := b.HandleRequest(req)
|
||||
if err != logical.ErrInvalidRequest {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if resp.Data["error"] != "unknown backend type: nope" {
|
||||
t.Fatalf("bad: %v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemBackend_disableAuth(t *testing.T) {
|
||||
c, b := testCoreSystemBackend(t)
|
||||
c.credentialBackends["noop"] = func(map[string]string) (credential.Backend, error) {
|
||||
return &NoopCred{}, nil
|
||||
}
|
||||
|
||||
// Register the backend
|
||||
req := logical.TestRequest(t, logical.WriteOperation, "auth/foo")
|
||||
req.Data["type"] = "noop"
|
||||
b.HandleRequest(req)
|
||||
|
||||
// Deregister it
|
||||
req = logical.TestRequest(t, logical.DeleteOperation, "auth/foo")
|
||||
resp, err := b.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if resp != nil {
|
||||
t.Fatalf("bad: %v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemBackend_disableAuth_invalid(t *testing.T) {
|
||||
b := testSystemBackend(t)
|
||||
|
||||
req := logical.TestRequest(t, logical.DeleteOperation, "auth/foo")
|
||||
resp, err := b.HandleRequest(req)
|
||||
if err != logical.ErrInvalidRequest {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if resp.Data["error"] != "no matching backend" {
|
||||
t.Fatalf("bad: %v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
func testSystemBackend(t *testing.T) logical.Backend {
|
||||
c, _ := TestCoreUnsealed(t)
|
||||
return NewSystemBackend(c)
|
||||
|
|
Loading…
Reference in New Issue