Add list support to certs in cert auth backend.

Fixes #1212
This commit is contained in:
Jeff Mitchell 2016-03-15 14:07:40 -04:00
parent 74ff117d03
commit 8bf935bc2b
4 changed files with 113 additions and 15 deletions

View File

@ -30,6 +30,7 @@ func Backend() *backend {
Paths: append([]*framework.Path{
pathConfig(&b),
pathLogin(&b),
pathListCerts(&b),
pathCerts(&b),
pathCRLs(&b),
}),

View File

@ -4,6 +4,7 @@ import (
"crypto/tls"
"fmt"
"io/ioutil"
"reflect"
"testing"
"time"
@ -44,14 +45,17 @@ func TestBackend_CertWrites(t *testing.T) {
if err != nil {
t.Fatalf("err: %v", err)
}
logicaltest.Test(t, logicaltest.TestCase{
tc := logicaltest.TestCase{
Backend: testFactory(t),
Steps: []logicaltest.TestStep{
testAccStepCert(t, "web", ca1, "foo", false),
testAccStepCert(t, "web", ca2, "foo", false),
testAccStepCert(t, "web", ca3, "foo", true),
testAccStepCert(t, "aaa", ca1, "foo", false),
testAccStepCert(t, "bbb", ca2, "foo", false),
testAccStepCert(t, "ccc", ca3, "foo", true),
},
})
}
tc.Steps = append(tc.Steps, testAccStepListCerts(t, []string{"aaa", "bbb"})...)
logicaltest.Test(t, tc)
}
// Test a client trusted by a CA
@ -183,7 +187,7 @@ func testAccStepLogin(t *testing.T, connState tls.ConnectionState) logicaltest.T
t.Fatalf("bad lease length: %#v", resp.Auth)
}
fn := logicaltest.TestCheckAuth([]string{"foo"})
fn := logicaltest.TestCheckAuth([]string{"default", "foo"})
return fn(resp)
},
}
@ -200,7 +204,7 @@ func testAccStepLoginDefaultLease(t *testing.T, connState tls.ConnectionState) l
t.Fatalf("bad lease length: %#v", resp.Auth)
}
fn := logicaltest.TestCheckAuth([]string{"foo"})
fn := logicaltest.TestCheckAuth([]string{"default", "foo"})
return fn(resp)
},
}
@ -222,6 +226,39 @@ func testAccStepLoginInvalid(t *testing.T, connState tls.ConnectionState) logica
}
}
func testAccStepListCerts(
t *testing.T, certs []string) []logicaltest.TestStep {
return []logicaltest.TestStep{
logicaltest.TestStep{
Operation: logical.ListOperation,
Path: "certs",
Check: func(resp *logical.Response) error {
if resp == nil {
return fmt.Errorf("nil response")
}
if resp.Data == nil {
return fmt.Errorf("nil data")
}
if resp.Data["keys"] == interface{}(nil) {
return fmt.Errorf("nil keys")
}
keys := resp.Data["keys"].([]string)
if !reflect.DeepEqual(keys, certs) {
return fmt.Errorf("mismatch: keys is %#v, certs is %#v", keys, certs)
}
return nil
},
}, logicaltest.TestStep{
Operation: logical.ListOperation,
Path: "certs/",
Check: func(resp *logical.Response) error {
return nil
},
},
}
}
func testAccStepCert(
t *testing.T, name string, cert []byte, policies string, expectError bool) logicaltest.TestStep {
return logicaltest.TestStep{

View File

@ -10,6 +10,19 @@ import (
"github.com/hashicorp/vault/logical/framework"
)
func pathListCerts(b *backend) *framework.Path {
return &framework.Path{
Pattern: "certs/?",
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ListOperation: b.pathCertList,
},
HelpSynopsis: pathCertHelpSyn,
HelpDescription: pathCertHelpDesc,
}
}
func pathCerts(b *backend) *framework.Path {
return &framework.Path{
Pattern: "certs/" + framework.GenericNameRegex("name"),
@ -85,6 +98,15 @@ func (b *backend) pathCertDelete(
return nil, nil
}
func (b *backend) pathCertList(
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
certs, err := req.Storage.List("cert/")
if err != nil {
return nil, err
}
return logical.ListResponse(certs), nil
}
func (b *backend) pathCertRead(
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
cert, err := b.Cert(req.Storage, strings.ToLower(d.Get("name").(string)))

View File

@ -124,7 +124,7 @@ of the header should be "X-Vault-Token" and the value should be the token.
<dl class="api">
<dt>Description</dt>
<dd>
Deletes the named role and CA cert from the backend mount. Requires `sudo` access.
Deletes the named role and CA cert from the backend mount.
</dd>
<dt>Method</dt>
@ -149,7 +149,7 @@ of the header should be "X-Vault-Token" and the value should be the token.
<dl class="api">
<dt>Description</dt>
<dd>
Gets information associated with the named role. Requires `sudo` access.
Gets information associated with the named role.
</dd>
<dt>Method</dt>
@ -185,12 +185,50 @@ of the header should be "X-Vault-Token" and the value should be the token.
</dd>
</dl>
#### LIST
<dl class="api">
<dt>Description</dt>
<dd>
Lists configured certificate names.
</dd>
<dt>Method</dt>
<dd>GET</dd>
<dt>URL</dt>
<dd>`/auth/cert/certs/<name>`</dd>
<dt>Parameters</dt>
<dd>
None
</dd>
<dt>Returns</dt>
<dd>
```javascript
{
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": {
"keys": ["cert1", "cert2"]
},
"warnings": null,
"auth": null
}
```
</dd>
</dl>
#### POST
<dl class="api">
<dt>Description</dt>
<dd>
Sets a CA cert and associated parameters in a role name. Requires `sudo` access.
Sets a CA cert and associated parameters in a role name.
</dd>
<dt>Method</dt>
@ -243,7 +281,7 @@ of the header should be "X-Vault-Token" and the value should be the token.
<dl class="api">
<dt>Description</dt>
<dd>
Deletes the named CRL from the backend mount. Requires `sudo` access.
Deletes the named CRL from the backend mount.
</dd>
<dt>Method</dt>
@ -268,9 +306,9 @@ of the header should be "X-Vault-Token" and the value should be the token.
<dl class="api">
<dt>Description</dt>
<dd>
Gets information associated with the named CRL (currently, the serial numbers contained within).
As the serials can be integers up to an arbitrary size, these are returned as strings. Requires
`sudo` access.
Gets information associated with the named CRL (currently, the serial
numbers contained within). As the serials can be integers up to an
arbitrary size, these are returned as strings.
</dd>
<dt>Method</dt>
@ -311,7 +349,7 @@ of the header should be "X-Vault-Token" and the value should be the token.
<dl class="api">
<dt>Description</dt>
<dd>
Sets a named CRL. Requires `sudo` access.
Sets a named CRL.
</dd>
<dt>Method</dt>