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{ Paths: append([]*framework.Path{
pathConfig(&b), pathConfig(&b),
pathLogin(&b), pathLogin(&b),
pathListCerts(&b),
pathCerts(&b), pathCerts(&b),
pathCRLs(&b), pathCRLs(&b),
}), }),

View file

@ -4,6 +4,7 @@ import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"reflect"
"testing" "testing"
"time" "time"
@ -44,14 +45,17 @@ func TestBackend_CertWrites(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
logicaltest.Test(t, logicaltest.TestCase{
tc := logicaltest.TestCase{
Backend: testFactory(t), Backend: testFactory(t),
Steps: []logicaltest.TestStep{ Steps: []logicaltest.TestStep{
testAccStepCert(t, "web", ca1, "foo", false), testAccStepCert(t, "aaa", ca1, "foo", false),
testAccStepCert(t, "web", ca2, "foo", false), testAccStepCert(t, "bbb", ca2, "foo", false),
testAccStepCert(t, "web", ca3, "foo", true), 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 // 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) t.Fatalf("bad lease length: %#v", resp.Auth)
} }
fn := logicaltest.TestCheckAuth([]string{"foo"}) fn := logicaltest.TestCheckAuth([]string{"default", "foo"})
return fn(resp) return fn(resp)
}, },
} }
@ -200,7 +204,7 @@ func testAccStepLoginDefaultLease(t *testing.T, connState tls.ConnectionState) l
t.Fatalf("bad lease length: %#v", resp.Auth) t.Fatalf("bad lease length: %#v", resp.Auth)
} }
fn := logicaltest.TestCheckAuth([]string{"foo"}) fn := logicaltest.TestCheckAuth([]string{"default", "foo"})
return fn(resp) 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( func testAccStepCert(
t *testing.T, name string, cert []byte, policies string, expectError bool) logicaltest.TestStep { t *testing.T, name string, cert []byte, policies string, expectError bool) logicaltest.TestStep {
return logicaltest.TestStep{ return logicaltest.TestStep{

View file

@ -10,6 +10,19 @@ import (
"github.com/hashicorp/vault/logical/framework" "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 { func pathCerts(b *backend) *framework.Path {
return &framework.Path{ return &framework.Path{
Pattern: "certs/" + framework.GenericNameRegex("name"), Pattern: "certs/" + framework.GenericNameRegex("name"),
@ -85,6 +98,15 @@ func (b *backend) pathCertDelete(
return nil, nil 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( func (b *backend) pathCertRead(
req *logical.Request, d *framework.FieldData) (*logical.Response, error) { req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
cert, err := b.Cert(req.Storage, strings.ToLower(d.Get("name").(string))) 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"> <dl class="api">
<dt>Description</dt> <dt>Description</dt>
<dd> <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> </dd>
<dt>Method</dt> <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"> <dl class="api">
<dt>Description</dt> <dt>Description</dt>
<dd> <dd>
Gets information associated with the named role. Requires `sudo` access. Gets information associated with the named role.
</dd> </dd>
<dt>Method</dt> <dt>Method</dt>
@ -185,12 +185,50 @@ of the header should be "X-Vault-Token" and the value should be the token.
</dd> </dd>
</dl> </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 #### POST
<dl class="api"> <dl class="api">
<dt>Description</dt> <dt>Description</dt>
<dd> <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> </dd>
<dt>Method</dt> <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"> <dl class="api">
<dt>Description</dt> <dt>Description</dt>
<dd> <dd>
Deletes the named CRL from the backend mount. Requires `sudo` access. Deletes the named CRL from the backend mount.
</dd> </dd>
<dt>Method</dt> <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"> <dl class="api">
<dt>Description</dt> <dt>Description</dt>
<dd> <dd>
Gets information associated with the named CRL (currently, the serial numbers contained within). Gets information associated with the named CRL (currently, the serial
As the serials can be integers up to an arbitrary size, these are returned as strings. Requires numbers contained within). As the serials can be integers up to an
`sudo` access. arbitrary size, these are returned as strings.
</dd> </dd>
<dt>Method</dt> <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"> <dl class="api">
<dt>Description</dt> <dt>Description</dt>
<dd> <dd>
Sets a named CRL. Requires `sudo` access. Sets a named CRL.
</dd> </dd>
<dt>Method</dt> <dt>Method</dt>