logical/framework: add methods to look up secret and gen response

This commit is contained in:
Mitchell Hashimoto
2015-03-19 14:59:01 +01:00
parent ef56daa3bc
commit b5757ae49a
5 changed files with 130 additions and 2 deletions

View File

@@ -106,6 +106,17 @@ func (b *Backend) Route(path string) *Path {
return result return result
} }
// Secret is used to look up the secret with the given type.
func (b *Backend) Secret(k string) *Secret {
for _, s := range b.Secrets {
if s.Type == k {
return s
}
}
return nil
}
func (b *Backend) init() { func (b *Backend) init() {
b.pathsRe = make([]*regexp.Regexp, len(b.Paths)) b.pathsRe = make([]*regexp.Regexp, len(b.Paths))
for i, p := range b.Paths { for i, p := range b.Paths {

View File

@@ -319,6 +319,37 @@ func TestBackendRoute(t *testing.T) {
} }
} }
func TestBackendSecret(t *testing.T) {
cases := map[string]struct {
Secrets []*Secret
Search string
Match bool
}{
"no match": {
[]*Secret{&Secret{Type: "foo"}},
"bar",
false,
},
"match": {
[]*Secret{&Secret{Type: "foo"}},
"foo",
true,
},
}
for n, tc := range cases {
b := &Backend{Secrets: tc.Secrets}
result := b.Secret(tc.Search)
if tc.Match != (result != nil) {
t.Fatalf("bad: %s\n\nExpected match: %v", n, tc.Match)
}
if result != nil && result.Type != tc.Search {
t.Fatalf("bad: %s\n\nExpected matching type: %#v", n, result)
}
}
}
func TestFieldSchemaDefaultOrZero(t *testing.T) { func TestFieldSchemaDefaultOrZero(t *testing.T) {
cases := map[string]struct { cases := map[string]struct {
Schema *FieldSchema Schema *FieldSchema

View File

@@ -7,7 +7,25 @@ import (
// Request is a single request for a backend that wraps a logical.Request // Request is a single request for a backend that wraps a logical.Request
// to provide some extra functionality. // to provide some extra functionality.
type Request struct { type Request struct {
Backend *Backend // Backend is the backend that generated this request.
Data *FieldData Backend *Backend
// Data is any parameters that were passed into the request according
// to the path schema. If this request is to a secret operation
// (revoke, renew), then Data is according to the schema of the
// secret.
Data *FieldData
// The fields below are only set for secret-related requests (renew,
// revoke).
//
// SecretType is the string type of the secret.
//
// SecretId is the ID of the secret that was given when generating
// the secret, or is otherwise just the UUID that was generated.
SecretType string
SecretId string
// LogicalRequest is the raw logical.Request structure for this request.
LogicalRequest *logical.Request LogicalRequest *logical.Request
} }

View File

@@ -1,13 +1,62 @@
package framework package framework
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/vault/logical"
)
// Secret is a type of secret that can be returned from a backend. // Secret is a type of secret that can be returned from a backend.
type Secret struct { type Secret struct {
// Type is the name of this secret type. This is used to setup the // Type is the name of this secret type. This is used to setup the
// vault ID and to look up the proper secret structure when revocation/ // vault ID and to look up the proper secret structure when revocation/
// renewal happens. Once this is set this should not be changed. // renewal happens. Once this is set this should not be changed.
//
// The format of this must match (case insensitive): ^a-Z0-9_$
Type string Type string
// Fields is the mapping of data fields and schema that comprise // Fields is the mapping of data fields and schema that comprise
// the structure of this secret. // the structure of this secret.
Fields map[string]*FieldSchema Fields map[string]*FieldSchema
// Renewable is whether or not this secret type can be renewed.
Renewable bool
// DefaultDuration and DefaultGracePeriod are the default values for
// the duration of the lease for this secret and its grace period. These
// can be manually overwritten with the result of Response().
DefaultDuration time.Duration
DefaultGracePeriod time.Duration
}
// SecretType is the type of the secret with the given ID.
func SecretType(id string) string {
idx := strings.Index(id, "-")
if idx < 0 {
return ""
}
return id[:idx]
}
func (s *Secret) Response(
data map[string]interface{}) (*logical.Response, error) {
uuid, err := logical.UUID()
if err != nil {
return nil, err
}
id := fmt.Sprintf("%s-%s", s.Type, uuid)
return &logical.Response{
IsSecret: true,
Lease: &logical.Lease{
VaultID: id,
Renewable: s.Renewable,
Duration: s.DefaultDuration,
GracePeriod: s.DefaultGracePeriod,
},
Data: data,
}, nil
} }

View File

@@ -0,0 +1,19 @@
package framework
import (
"testing"
)
func TestSecretType(t *testing.T) {
cases := [][2]string{
{"foo-bar", "foo"},
{"foo", ""},
}
for _, tc := range cases {
actual := SecretType(tc[0])
if actual != tc[1] {
t.Fatalf("Input: %s, Output: %s, Expected: %s", tc[0], actual, tc[1])
}
}
}