Merge branch 'master-oss' into cubbyhole-the-world

This commit is contained in:
Jeff Mitchell
2016-05-19 02:43:22 +00:00
19 changed files with 153 additions and 54 deletions

View File

@@ -78,6 +78,7 @@ IMPROVEMENTS:
backend [GH-1404] backend [GH-1404]
* credential/ldap: If `groupdn` is not configured, skip searching LDAP and * credential/ldap: If `groupdn` is not configured, skip searching LDAP and
only return policies for local groups, plus a warning [GH-1283] only return policies for local groups, plus a warning [GH-1283]
* credential/ldap: `vault list` support for users and groups [GH-1270]
* credential/userpass: Add list support for users [GH-911] * credential/userpass: Add list support for users [GH-911]
* credential/userpass: Remove user configuration paths from requiring sudo, in * credential/userpass: Remove user configuration paths from requiring sudo, in
favor of normal ACL mechanisms [GH-1312] favor of normal ACL mechanisms [GH-1312]
@@ -114,6 +115,8 @@ BUG FIXES:
* credential/various: Fix renewal conditions when `default` policy is not * credential/various: Fix renewal conditions when `default` policy is not
contained in the backend config [GH-1256] contained in the backend config [GH-1256]
* physical/s3: Don't panic in certain error cases from bad S3 responses [GH-1353] * physical/s3: Don't panic in certain error cases from bad S3 responses [GH-1353]
* secret/consul: Use non-pooled Consul API client to avoid leaving files open
[GH-1428]
* secret/pki: Don't check whether a certificate is destined to be a CA * secret/pki: Don't check whether a certificate is destined to be a CA
certificate if sign-verbatim endpoint is used [GH-1250] certificate if sign-verbatim endpoint is used [GH-1250]

View File

@@ -114,7 +114,7 @@ func (b *backend) periodicFunc(req *logical.Request) error {
if b.nextTidyTime.IsZero() || !time.Now().UTC().Before(b.nextTidyTime) { if b.nextTidyTime.IsZero() || !time.Now().UTC().Before(b.nextTidyTime) {
// safety_buffer defaults to 180 days for roletag blacklist // safety_buffer defaults to 180 days for roletag blacklist
safety_buffer := 15552000 safety_buffer := 15552000
tidyBlacklistConfigEntry, err := b.configTidyRoleTags(req.Storage) tidyBlacklistConfigEntry, err := b.lockedConfigTidyRoleTags(req.Storage)
if err != nil { if err != nil {
return err return err
} }
@@ -135,7 +135,7 @@ func (b *backend) periodicFunc(req *logical.Request) error {
// reset the safety_buffer to 72h // reset the safety_buffer to 72h
safety_buffer = 259200 safety_buffer = 259200
tidyWhitelistConfigEntry, err := b.configTidyIdentities(req.Storage) tidyWhitelistConfigEntry, err := b.lockedConfigTidyIdentities(req.Storage)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -98,7 +98,7 @@ func TestBackend_CreateParseVerifyRoleTag(t *testing.T) {
} }
// read the created role entry // read the created role entry
roleEntry, err := b.awsRole(storage, "abcd-123") roleEntry, err := b.lockedAWSRole(storage, "abcd-123")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -165,7 +165,7 @@ func TestBackend_CreateParseVerifyRoleTag(t *testing.T) {
} }
// get the entry of the newly created role entry // get the entry of the newly created role entry
roleEntry2, err := b.awsRole(storage, "ami-6789") roleEntry2, err := b.lockedAWSRole(storage, "ami-6789")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -1098,7 +1098,7 @@ func TestBackend_PathBlacklistRoleTag(t *testing.T) {
} }
// try to read the deleted entry // try to read the deleted entry
tagEntry, err := b.blacklistRoleTagEntry(storage, tag) tagEntry, err := b.lockedBlacklistRoleTagEntry(storage, tag)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -24,7 +24,7 @@ func (b *backend) getClientConfig(s logical.Storage, region string) (*aws.Config
} }
// Read the configured secret key and access key // Read the configured secret key and access key
config, err := b.clientConfigEntryInternal(s) config, err := b.nonLockedClientConfigEntry(s)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -96,7 +96,7 @@ func (b *backend) pathConfigCertificateExistenceCheck(req *logical.Request, data
return false, fmt.Errorf("missing cert_name") return false, fmt.Errorf("missing cert_name")
} }
entry, err := b.awsPublicCertificateEntry(req.Storage, certName) entry, err := b.lockedAWSPublicCertificateEntry(req.Storage, certName)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -161,7 +161,7 @@ func (b *backend) awsPublicCertificates(s logical.Storage) ([]*x509.Certificate,
// Iterate through each certificate, parse and append it to a slice. // Iterate through each certificate, parse and append it to a slice.
for _, cert := range registeredCerts { for _, cert := range registeredCerts {
certEntry, err := b.awsPublicCertificateEntryInternal(s, cert) certEntry, err := b.nonLockedAWSPublicCertificateEntry(s, cert)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -180,15 +180,15 @@ func (b *backend) awsPublicCertificates(s logical.Storage) ([]*x509.Certificate,
// awsPublicCertificate is used to get the configured AWS Public Key that is used // awsPublicCertificate is used to get the configured AWS Public Key that is used
// to verify the PKCS#7 signature of the instance identity document. // to verify the PKCS#7 signature of the instance identity document.
func (b *backend) awsPublicCertificateEntry(s logical.Storage, certName string) (*awsPublicCert, error) { func (b *backend) lockedAWSPublicCertificateEntry(s logical.Storage, certName string) (*awsPublicCert, error) {
b.configMutex.RLock() b.configMutex.RLock()
defer b.configMutex.RUnlock() defer b.configMutex.RUnlock()
return b.awsPublicCertificateEntryInternal(s, certName) return b.nonLockedAWSPublicCertificateEntry(s, certName)
} }
// Internal version of the above that does no locking // Internal version of the above that does no locking
func (b *backend) awsPublicCertificateEntryInternal(s logical.Storage, certName string) (*awsPublicCert, error) { func (b *backend) nonLockedAWSPublicCertificateEntry(s logical.Storage, certName string) (*awsPublicCert, error) {
entry, err := s.Get("config/certificate/" + certName) entry, err := s.Get("config/certificate/" + certName)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -227,7 +227,7 @@ func (b *backend) pathConfigCertificateRead(
return logical.ErrorResponse("missing cert_name"), nil return logical.ErrorResponse("missing cert_name"), nil
} }
certificateEntry, err := b.awsPublicCertificateEntry(req.Storage, certName) certificateEntry, err := b.lockedAWSPublicCertificateEntry(req.Storage, certName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -253,7 +253,7 @@ func (b *backend) pathConfigCertificateCreateUpdate(
defer b.configMutex.Unlock() defer b.configMutex.Unlock()
// Check if there is already a certificate entry registered. // Check if there is already a certificate entry registered.
certEntry, err := b.awsPublicCertificateEntryInternal(req.Storage, certName) certEntry, err := b.nonLockedAWSPublicCertificateEntry(req.Storage, certName)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -48,23 +48,23 @@ func pathConfigClient(b *backend) *framework.Path {
func (b *backend) pathConfigClientExistenceCheck( func (b *backend) pathConfigClientExistenceCheck(
req *logical.Request, data *framework.FieldData) (bool, error) { req *logical.Request, data *framework.FieldData) (bool, error) {
entry, err := b.clientConfigEntry(req.Storage) entry, err := b.lockedClientConfigEntry(req.Storage)
if err != nil { if err != nil {
return false, err return false, err
} }
return entry != nil, nil return entry != nil, nil
} }
// Fetch the client configuration required to access the AWS API. // Fetch the client configuration required to access the AWS API, after acquiring an exclusive lock.
func (b *backend) clientConfigEntry(s logical.Storage) (*clientConfig, error) { func (b *backend) lockedClientConfigEntry(s logical.Storage) (*clientConfig, error) {
b.configMutex.RLock() b.configMutex.RLock()
defer b.configMutex.RUnlock() defer b.configMutex.RUnlock()
return b.clientConfigEntryInternal(s) return b.nonLockedClientConfigEntry(s)
} }
// Internal version that does no locking // Fetch the client configuration required to access the AWS API.
func (b *backend) clientConfigEntryInternal(s logical.Storage) (*clientConfig, error) { func (b *backend) nonLockedClientConfigEntry(s logical.Storage) (*clientConfig, error) {
entry, err := s.Get("config/client") entry, err := s.Get("config/client")
if err != nil { if err != nil {
return nil, err return nil, err
@@ -82,7 +82,7 @@ func (b *backend) clientConfigEntryInternal(s logical.Storage) (*clientConfig, e
func (b *backend) pathConfigClientRead( func (b *backend) pathConfigClientRead(
req *logical.Request, data *framework.FieldData) (*logical.Response, error) { req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
clientConfig, err := b.clientConfigEntry(req.Storage) clientConfig, err := b.lockedClientConfigEntry(req.Storage)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -118,7 +118,7 @@ func (b *backend) pathConfigClientCreateUpdate(
b.configMutex.Lock() b.configMutex.Lock()
defer b.configMutex.Unlock() defer b.configMutex.Unlock()
configEntry, err := b.clientConfigEntryInternal(req.Storage) configEntry, err := b.nonLockedClientConfigEntry(req.Storage)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -44,21 +44,21 @@ expiration, before it is removed from the backend storage.`,
} }
func (b *backend) pathConfigTidyIdentityWhitelistExistenceCheck(req *logical.Request, data *framework.FieldData) (bool, error) { func (b *backend) pathConfigTidyIdentityWhitelistExistenceCheck(req *logical.Request, data *framework.FieldData) (bool, error) {
entry, err := b.configTidyIdentities(req.Storage) entry, err := b.lockedConfigTidyIdentities(req.Storage)
if err != nil { if err != nil {
return false, err return false, err
} }
return entry != nil, nil return entry != nil, nil
} }
func (b *backend) configTidyIdentities(s logical.Storage) (*tidyWhitelistIdentityConfig, error) { func (b *backend) lockedConfigTidyIdentities(s logical.Storage) (*tidyWhitelistIdentityConfig, error) {
b.configMutex.RLock() b.configMutex.RLock()
defer b.configMutex.RUnlock() defer b.configMutex.RUnlock()
return b.configTidyIdentitiesInternal(s) return b.nonLockedConfigTidyIdentities(s)
} }
func (b *backend) configTidyIdentitiesInternal(s logical.Storage) (*tidyWhitelistIdentityConfig, error) { func (b *backend) nonLockedConfigTidyIdentities(s logical.Storage) (*tidyWhitelistIdentityConfig, error) {
entry, err := s.Get(identityWhitelistConfigPath) entry, err := s.Get(identityWhitelistConfigPath)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -78,7 +78,7 @@ func (b *backend) pathConfigTidyIdentityWhitelistCreateUpdate(req *logical.Reque
b.configMutex.Lock() b.configMutex.Lock()
defer b.configMutex.Unlock() defer b.configMutex.Unlock()
configEntry, err := b.configTidyIdentitiesInternal(req.Storage) configEntry, err := b.nonLockedConfigTidyIdentities(req.Storage)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -113,7 +113,7 @@ func (b *backend) pathConfigTidyIdentityWhitelistCreateUpdate(req *logical.Reque
} }
func (b *backend) pathConfigTidyIdentityWhitelistRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) { func (b *backend) pathConfigTidyIdentityWhitelistRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
clientConfig, err := b.configTidyIdentities(req.Storage) clientConfig, err := b.lockedConfigTidyIdentities(req.Storage)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -46,21 +46,21 @@ Defaults to 4320h (180 days).`,
} }
func (b *backend) pathConfigTidyRoletagBlacklistExistenceCheck(req *logical.Request, data *framework.FieldData) (bool, error) { func (b *backend) pathConfigTidyRoletagBlacklistExistenceCheck(req *logical.Request, data *framework.FieldData) (bool, error) {
entry, err := b.configTidyRoleTags(req.Storage) entry, err := b.lockedConfigTidyRoleTags(req.Storage)
if err != nil { if err != nil {
return false, err return false, err
} }
return entry != nil, nil return entry != nil, nil
} }
func (b *backend) configTidyRoleTags(s logical.Storage) (*tidyBlacklistRoleTagConfig, error) { func (b *backend) lockedConfigTidyRoleTags(s logical.Storage) (*tidyBlacklistRoleTagConfig, error) {
b.configMutex.RLock() b.configMutex.RLock()
defer b.configMutex.RUnlock() defer b.configMutex.RUnlock()
return b.configTidyRoleTagsInternal(s) return b.nonLockedConfigTidyRoleTags(s)
} }
func (b *backend) configTidyRoleTagsInternal(s logical.Storage) (*tidyBlacklistRoleTagConfig, error) { func (b *backend) nonLockedConfigTidyRoleTags(s logical.Storage) (*tidyBlacklistRoleTagConfig, error) {
entry, err := s.Get(roletagBlacklistConfigPath) entry, err := s.Get(roletagBlacklistConfigPath)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -81,7 +81,7 @@ func (b *backend) pathConfigTidyRoletagBlacklistCreateUpdate(req *logical.Reques
b.configMutex.Lock() b.configMutex.Lock()
defer b.configMutex.Unlock() defer b.configMutex.Unlock()
configEntry, err := b.configTidyRoleTagsInternal(req.Storage) configEntry, err := b.nonLockedConfigTidyRoleTags(req.Storage)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -114,7 +114,7 @@ func (b *backend) pathConfigTidyRoletagBlacklistCreateUpdate(req *logical.Reques
} }
func (b *backend) pathConfigTidyRoletagBlacklistRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) { func (b *backend) pathConfigTidyRoletagBlacklistRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
clientConfig, err := b.configTidyRoleTags(req.Storage) clientConfig, err := b.lockedConfigTidyRoleTags(req.Storage)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -236,7 +236,7 @@ func (b *backend) pathLoginUpdate(
} }
// Get the entry for the role used by the instance. // Get the entry for the role used by the instance.
roleEntry, err := b.awsRole(req.Storage, roleName) roleEntry, err := b.lockedAWSRole(req.Storage, roleName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -442,7 +442,7 @@ func (b *backend) handleRoleTagLogin(s logical.Storage, identityDoc *identityDoc
} }
// Check if the role tag is blacklisted. // Check if the role tag is blacklisted.
blacklistEntry, err := b.blacklistRoleTagEntry(s, rTagValue) blacklistEntry, err := b.lockedBlacklistRoleTagEntry(s, rTagValue)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -487,7 +487,7 @@ func (b *backend) pathLoginRenew(
} }
// Ensure that role entry is not deleted. // Ensure that role entry is not deleted.
roleEntry, err := b.awsRole(req.Storage, storedIdentity.Role) roleEntry, err := b.lockedAWSRole(req.Storage, storedIdentity.Role)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -101,7 +101,7 @@ func pathListRoles(b *backend) *framework.Path {
// Establishes dichotomy of request operation between CreateOperation and UpdateOperation. // Establishes dichotomy of request operation between CreateOperation and UpdateOperation.
// Returning 'true' forces an UpdateOperation, CreateOperation otherwise. // Returning 'true' forces an UpdateOperation, CreateOperation otherwise.
func (b *backend) pathRoleExistenceCheck(req *logical.Request, data *framework.FieldData) (bool, error) { func (b *backend) pathRoleExistenceCheck(req *logical.Request, data *framework.FieldData) (bool, error) {
entry, err := b.awsRole(req.Storage, strings.ToLower(data.Get("role").(string))) entry, err := b.lockedAWSRole(req.Storage, strings.ToLower(data.Get("role").(string)))
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -109,14 +109,14 @@ func (b *backend) pathRoleExistenceCheck(req *logical.Request, data *framework.F
} }
// awsRole is used to get the information registered for the given AMI ID. // awsRole is used to get the information registered for the given AMI ID.
func (b *backend) awsRole(s logical.Storage, role string) (*awsRoleEntry, error) { func (b *backend) lockedAWSRole(s logical.Storage, role string) (*awsRoleEntry, error) {
b.roleMutex.RLock() b.roleMutex.RLock()
defer b.roleMutex.RUnlock() defer b.roleMutex.RUnlock()
return b.awsRoleInternal(s, role) return b.nonLockedAWSRole(s, role)
} }
func (b *backend) awsRoleInternal(s logical.Storage, role string) (*awsRoleEntry, error) { func (b *backend) nonLockedAWSRole(s logical.Storage, role string) (*awsRoleEntry, error) {
entry, err := s.Get("role/" + strings.ToLower(role)) entry, err := s.Get("role/" + strings.ToLower(role))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -162,7 +162,7 @@ func (b *backend) pathRoleList(
// pathRoleRead is used to view the information registered for a given AMI ID. // pathRoleRead is used to view the information registered for a given AMI ID.
func (b *backend) pathRoleRead( func (b *backend) pathRoleRead(
req *logical.Request, data *framework.FieldData) (*logical.Response, error) { req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
roleEntry, err := b.awsRole(req.Storage, strings.ToLower(data.Get("role").(string))) roleEntry, err := b.lockedAWSRole(req.Storage, strings.ToLower(data.Get("role").(string)))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -196,7 +196,7 @@ func (b *backend) pathRoleCreateUpdate(
b.roleMutex.Lock() b.roleMutex.Lock()
defer b.roleMutex.Unlock() defer b.roleMutex.Unlock()
roleEntry, err := b.awsRoleInternal(req.Storage, roleName) roleEntry, err := b.nonLockedAWSRole(req.Storage, roleName)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -78,7 +78,7 @@ func (b *backend) pathRoleTagUpdate(
} }
// Fetch the role entry // Fetch the role entry
roleEntry, err := b.awsRole(req.Storage, roleName) roleEntry, err := b.lockedAWSRole(req.Storage, roleName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -346,7 +346,7 @@ func (b *backend) parseAndVerifyRoleTagValue(s logical.Storage, tag string) (*ro
return nil, fmt.Errorf("missing role name") return nil, fmt.Errorf("missing role name")
} }
roleEntry, err := b.awsRole(s, rTag.Role) roleEntry, err := b.lockedAWSRole(s, rTag.Role)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -72,14 +72,14 @@ func (b *backend) pathRoletagBlacklistsList(
// Fetch an entry from the role tag blacklist for a given tag. // Fetch an entry from the role tag blacklist for a given tag.
// This method takes a role tag in its original form and not a base64 encoded form. // This method takes a role tag in its original form and not a base64 encoded form.
func (b *backend) blacklistRoleTagEntry(s logical.Storage, tag string) (*roleTagBlacklistEntry, error) { func (b *backend) lockedBlacklistRoleTagEntry(s logical.Storage, tag string) (*roleTagBlacklistEntry, error) {
b.blacklistMutex.RLock() b.blacklistMutex.RLock()
defer b.blacklistMutex.RUnlock() defer b.blacklistMutex.RUnlock()
return b.blacklistRoleTagEntryInternal(s, tag) return b.nonLockedBlacklistRoleTagEntry(s, tag)
} }
func (b *backend) blacklistRoleTagEntryInternal(s logical.Storage, tag string) (*roleTagBlacklistEntry, error) { func (b *backend) nonLockedBlacklistRoleTagEntry(s logical.Storage, tag string) (*roleTagBlacklistEntry, error) {
entry, err := s.Get("blacklist/roletag/" + base64.StdEncoding.EncodeToString([]byte(tag))) entry, err := s.Get("blacklist/roletag/" + base64.StdEncoding.EncodeToString([]byte(tag)))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -119,7 +119,7 @@ func (b *backend) pathRoletagBlacklistRead(
return logical.ErrorResponse("missing role_tag"), nil return logical.ErrorResponse("missing role_tag"), nil
} }
entry, err := b.blacklistRoleTagEntry(req.Storage, tag) entry, err := b.lockedBlacklistRoleTagEntry(req.Storage, tag)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -166,7 +166,7 @@ func (b *backend) pathRoletagBlacklistUpdate(
} }
// Get the entry for the role mentioned in the role tag. // Get the entry for the role mentioned in the role tag.
roleEntry, err := b.awsRole(req.Storage, rTag.Role) roleEntry, err := b.lockedAWSRole(req.Storage, rTag.Role)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -178,7 +178,7 @@ func (b *backend) pathRoletagBlacklistUpdate(
defer b.blacklistMutex.Unlock() defer b.blacklistMutex.Unlock()
// Check if the role tag is already blacklisted. If yes, update it. // Check if the role tag is already blacklisted. If yes, update it.
blEntry, err := b.blacklistRoleTagEntryInternal(req.Storage, tag) blEntry, err := b.nonLockedBlacklistRoleTagEntry(req.Storage, tag)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -35,7 +35,9 @@ func Backend() *framework.Backend {
Paths: append([]*framework.Path{ Paths: append([]*framework.Path{
pathConfig(&b), pathConfig(&b),
pathGroups(&b), pathGroups(&b),
pathGroupsList(&b),
pathUsers(&b), pathUsers(&b),
pathUsersList(&b),
}, },
mfa.MFAPaths(b.Backend, pathLogin(&b))..., mfa.MFAPaths(b.Backend, pathLogin(&b))...,
), ),

View File

@@ -2,6 +2,7 @@ package ldap
import ( import (
"fmt" "fmt"
"reflect"
"testing" "testing"
"time" "time"
@@ -38,6 +39,8 @@ func TestBackend_basic(t *testing.T) {
testAccStepGroup(t, "engineers", "bar"), testAccStepGroup(t, "engineers", "bar"),
testAccStepUser(t, "tesla", "engineers"), testAccStepUser(t, "tesla", "engineers"),
testAccStepLogin(t, "tesla", "password"), testAccStepLogin(t, "tesla", "password"),
testAccStepGroupList(t, []string{"engineers", "scientists"}),
testAccStepUserList(t, []string{"tesla"}),
}, },
}) })
} }
@@ -321,3 +324,39 @@ func TestLDAPEscape(t *testing.T) {
} }
} }
} }
func testAccStepGroupList(t *testing.T, groups []string) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.ListOperation,
Path: "groups",
Check: func(resp *logical.Response) error {
if resp.IsError() {
return fmt.Errorf("Got error response: %#v", *resp)
}
exp := groups
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 testAccStepUserList(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 := users
if !reflect.DeepEqual(exp, resp.Data["keys"].([]string)) {
return fmt.Errorf("expected:\n%#v\ngot:\n%#v\n", exp, resp.Data["keys"])
}
return nil
},
}
}

View File

@@ -8,6 +8,19 @@ import (
"github.com/hashicorp/vault/logical/framework" "github.com/hashicorp/vault/logical/framework"
) )
func pathGroupsList(b *backend) *framework.Path {
return &framework.Path{
Pattern: "groups/?$",
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ListOperation: b.pathGroupList,
},
HelpSynopsis: pathGroupHelpSyn,
HelpDescription: pathGroupHelpDesc,
}
}
func pathGroups(b *backend) *framework.Path { func pathGroups(b *backend) *framework.Path {
return &framework.Path{ return &framework.Path{
Pattern: `groups/(?P<name>.+)`, Pattern: `groups/(?P<name>.+)`,
@@ -94,6 +107,15 @@ func (b *backend) pathGroupWrite(
return nil, nil return nil, nil
} }
func (b *backend) pathGroupList(
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
groups, err := req.Storage.List("group/")
if err != nil {
return nil, err
}
return logical.ListResponse(groups), nil
}
type GroupEntry struct { type GroupEntry struct {
Policies []string Policies []string
} }

View File

@@ -7,6 +7,19 @@ import (
"github.com/hashicorp/vault/logical/framework" "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 { func pathUsers(b *backend) *framework.Path {
return &framework.Path{ return &framework.Path{
Pattern: `users/(?P<name>.+)`, Pattern: `users/(?P<name>.+)`,
@@ -25,7 +38,7 @@ func pathUsers(b *backend) *framework.Path {
Callbacks: map[logical.Operation]framework.OperationFunc{ Callbacks: map[logical.Operation]framework.OperationFunc{
logical.DeleteOperation: b.pathUserDelete, logical.DeleteOperation: b.pathUserDelete,
logical.ReadOperation: b.pathUserRead, logical.ReadOperation: b.pathUserRead,
logical.UpdateOperation: b.pathUserWrite, logical.UpdateOperation: b.pathUserWrite,
}, },
HelpSynopsis: pathUserHelpSyn, HelpSynopsis: pathUserHelpSyn,
@@ -99,6 +112,15 @@ func (b *backend) pathUserWrite(
return nil, nil return nil, nil
} }
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
}
type UserEntry struct { type UserEntry struct {
Groups []string Groups []string
} }

View File

@@ -23,7 +23,7 @@ func client(s logical.Storage) (*api.Client, error) {
return nil, fmt.Errorf("error reading root configuration: %s", err) return nil, fmt.Errorf("error reading root configuration: %s", err)
} }
consulConf := api.DefaultConfig() consulConf := api.DefaultNonPooledConfig()
consulConf.Address = conf.Address consulConf.Address = conf.Address
consulConf.Scheme = conf.Scheme consulConf.Scheme = conf.Scheme
consulConf.Token = conf.Token consulConf.Token = conf.Token

View File

@@ -129,12 +129,17 @@ func (t TableFormatter) OutputSecret(ui cli.Ui, secret, s *api.Secret) error {
input = append(input, fmt.Sprintf("Key %s Value", config.Delim)) input = append(input, fmt.Sprintf("Key %s Value", config.Delim))
input = append(input, fmt.Sprintf("--- %s -----", config.Delim))
if s.LeaseDuration > 0 { if s.LeaseDuration > 0 {
if s.LeaseID != "" { if s.LeaseID != "" {
input = append(input, fmt.Sprintf("lease_id %s %s", config.Delim, s.LeaseID)) input = append(input, fmt.Sprintf("lease_id %s %s", config.Delim, s.LeaseID))
input = append(input, fmt.Sprintf(
"lease_duration %s %d", config.Delim, s.LeaseDuration))
} else {
input = append(input, fmt.Sprintf(
"refresh_interval %s %d", config.Delim, s.LeaseDuration))
} }
input = append(input, fmt.Sprintf(
"lease_duration %s %d", config.Delim, s.LeaseDuration))
if s.LeaseID != "" { if s.LeaseID != "" {
input = append(input, fmt.Sprintf( input = append(input, fmt.Sprintf(
"lease_renewable %s %s", config.Delim, strconv.FormatBool(s.Renewable))) "lease_renewable %s %s", config.Delim, strconv.FormatBool(s.Renewable)))

View File

@@ -23,6 +23,12 @@ active, dedicated users willing to help you through various mediums.
<a href="https://github.com/hashicorp/vault/issues">Issue tracker <a href="https://github.com/hashicorp/vault/issues">Issue tracker
on GitHub</a>. Please only use this for reporting bugs. Do not ask on GitHub</a>. Please only use this for reporting bugs. Do not ask
for general help here. Use IRC or the mailing list for that. for general help here. Use IRC or the mailing list for that.
</p>
<p>
<strong>Training:</strong>
Paid <a href="https://www.hashicorp.com/training.html">HashiCorp training courses</a>
are also available in a city near you. Private training courses are also available.
</p>
<h1>People</h1> <h1>People</h1>
<p> <p>