mirror of
https://github.com/hashicorp/vault.git
synced 2026-05-28 04:10:44 -04:00
Add list support to userpass users. Remove some unneeded existence
checks. Remove paths from requiring root. Fixes #911
This commit is contained in:
parent
363f517232
commit
ca221009d4
5 changed files with 52 additions and 25 deletions
|
|
@ -16,11 +16,7 @@ func Backend() *framework.Backend {
|
|||
Help: backendHelp,
|
||||
|
||||
PathsSpecial: &logical.Paths{
|
||||
Root: append([]string{
|
||||
"users/*",
|
||||
},
|
||||
mfa.MFARootPaths()...,
|
||||
),
|
||||
Root: mfa.MFARootPaths(),
|
||||
|
||||
Unauthenticated: []string{
|
||||
"login/*",
|
||||
|
|
@ -29,6 +25,7 @@ func Backend() *framework.Backend {
|
|||
|
||||
Paths: append([]*framework.Path{
|
||||
pathUsers(&b),
|
||||
pathUsersList(&b),
|
||||
pathUserPolicies(&b),
|
||||
pathUserPassword(&b),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package userpass
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -83,6 +84,9 @@ func TestBackend_basic(t *testing.T) {
|
|||
Backend: b,
|
||||
Steps: []logicaltest.TestStep{
|
||||
testAccStepUser(t, "web", "password", "foo"),
|
||||
testAccStepUser(t, "web2", "password", "foo"),
|
||||
testAccStepUser(t, "web3", "password", "foo"),
|
||||
testAccStepList(t, []string{"web", "web2", "web3"}),
|
||||
testAccStepLogin(t, "web", "password", []string{"default", "foo"}),
|
||||
},
|
||||
})
|
||||
|
|
@ -105,7 +109,7 @@ func TestBackend_userCrud(t *testing.T) {
|
|||
Backend: b,
|
||||
Steps: []logicaltest.TestStep{
|
||||
testAccStepUser(t, "web", "password", "foo"),
|
||||
testAccStepReadUser(t, "web", "foo"),
|
||||
testAccStepReadUser(t, "web", "default,foo"),
|
||||
testAccStepDeleteUser(t, "web"),
|
||||
testAccStepReadUser(t, "web", ""),
|
||||
},
|
||||
|
|
@ -151,7 +155,7 @@ func TestBackend_passwordUpdate(t *testing.T) {
|
|||
Backend: b,
|
||||
Steps: []logicaltest.TestStep{
|
||||
testAccStepUser(t, "web", "password", "foo"),
|
||||
testAccStepReadUser(t, "web", "foo"),
|
||||
testAccStepReadUser(t, "web", "default,foo"),
|
||||
testAccStepLogin(t, "web", "password", []string{"default", "foo"}),
|
||||
testUpdatePassword(t, "web", "newpassword"),
|
||||
testAccStepLogin(t, "web", "newpassword", []string{"default", "foo"}),
|
||||
|
|
@ -177,10 +181,10 @@ func TestBackend_policiesUpdate(t *testing.T) {
|
|||
Backend: b,
|
||||
Steps: []logicaltest.TestStep{
|
||||
testAccStepUser(t, "web", "password", "foo"),
|
||||
testAccStepReadUser(t, "web", "foo"),
|
||||
testAccStepReadUser(t, "web", "default,foo"),
|
||||
testAccStepLogin(t, "web", "password", []string{"default", "foo"}),
|
||||
testUpdatePolicies(t, "web", "foo,bar"),
|
||||
testAccStepReadUser(t, "web", "foo,bar"),
|
||||
testAccStepReadUser(t, "web", "bar,default,foo"),
|
||||
testAccStepLogin(t, "web", "password", []string{"bar", "default", "foo"}),
|
||||
},
|
||||
})
|
||||
|
|
@ -237,6 +241,24 @@ func testLoginWrite(t *testing.T, user string, data map[string]interface{}, expe
|
|||
}
|
||||
}
|
||||
|
||||
func testAccStepList(t *testing.T, users []string) logicaltest.TestStep {
|
||||
return logicaltest.TestStep{
|
||||
Operation: logical.ListOperation,
|
||||
Path: "users",
|
||||
Check: func(resp *logical.Response) error {
|
||||
if resp.IsError() {
|
||||
return fmt.Errorf("Got error response: %#v", *resp)
|
||||
}
|
||||
|
||||
exp := []string{"web", "web2", "web3"}
|
||||
if !reflect.DeepEqual(exp, resp.Data["keys"].([]string)) {
|
||||
return fmt.Errorf("expected:\n%#v\ngot:\n%#v\n", exp, resp.Data["keys"])
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testAccStepLogin(t *testing.T, user string, pass string, policies []string) logicaltest.TestStep {
|
||||
return logicaltest.TestStep{
|
||||
Operation: logical.UpdateOperation,
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ func pathUserPassword(b *backend) *framework.Path {
|
|||
},
|
||||
},
|
||||
|
||||
ExistenceCheck: b.userPasswordExistenceCheck,
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
logical.UpdateOperation: b.pathUserPasswordUpdate,
|
||||
},
|
||||
|
|
@ -35,12 +33,6 @@ func pathUserPassword(b *backend) *framework.Path {
|
|||
}
|
||||
}
|
||||
|
||||
// By always returning true, this endpoint will be enforced to be invoked only upon UpdateOperation.
|
||||
// The existence of user will be checked in the operation handler.
|
||||
func (b *backend) userPasswordExistenceCheck(req *logical.Request, data *framework.FieldData) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (b *backend) pathUserPasswordUpdate(
|
||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@ func pathUserPolicies(b *backend) *framework.Path {
|
|||
},
|
||||
},
|
||||
|
||||
ExistenceCheck: b.userPoliciesExistenceCheck,
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
logical.UpdateOperation: b.pathUserPoliciesUpdate,
|
||||
},
|
||||
|
|
@ -33,12 +31,6 @@ func pathUserPolicies(b *backend) *framework.Path {
|
|||
}
|
||||
}
|
||||
|
||||
// By always returning true, this endpoint will be enforced to be invoked only upon UpdateOperation.
|
||||
// The existence of user will be checked in the operation handler.
|
||||
func (b *backend) userPoliciesExistenceCheck(req *logical.Request, data *framework.FieldData) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (b *backend) pathUserPoliciesUpdate(
|
||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,19 @@ import (
|
|||
"github.com/hashicorp/vault/logical/framework"
|
||||
)
|
||||
|
||||
func pathUsersList(b *backend) *framework.Path {
|
||||
return &framework.Path{
|
||||
Pattern: "users/?",
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
logical.ListOperation: b.pathUserList,
|
||||
},
|
||||
|
||||
HelpSynopsis: pathUserHelpSyn,
|
||||
HelpDescription: pathUserHelpDesc,
|
||||
}
|
||||
}
|
||||
|
||||
func pathUsers(b *backend) *framework.Path {
|
||||
return &framework.Path{
|
||||
Pattern: "users/" + framework.GenericNameRegex("username"),
|
||||
|
|
@ -93,6 +106,15 @@ func (b *backend) setUser(s logical.Storage, username string, userEntry *UserEnt
|
|||
return s.Put(entry)
|
||||
}
|
||||
|
||||
func (b *backend) pathUserList(
|
||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
users, err := req.Storage.List("user/")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return logical.ListResponse(users), nil
|
||||
}
|
||||
|
||||
func (b *backend) pathUserDelete(
|
||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
err := req.Storage.Delete("user/" + strings.ToLower(d.Get("username").(string)))
|
||||
|
|
@ -116,6 +138,8 @@ func (b *backend) pathUserRead(
|
|||
return &logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
"policies": strings.Join(user.Policies, ","),
|
||||
"ttl": user.TTL.Seconds(),
|
||||
"max_ttl": user.MaxTTL.Seconds(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue