2015-03-11 22:49:11 +00:00
|
|
|
package vault
|
2015-03-06 00:35:09 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// GenericBackend is used for the storing generic secrets. These are not
|
|
|
|
// materialized in any way. The value that is written to this backend
|
|
|
|
// is the same value that is always returned. Leasing can be configured on
|
|
|
|
// a per-key basis.
|
|
|
|
type GenericBackend struct{}
|
|
|
|
|
|
|
|
// newGenericBackend is a factory constructor for the generic backend
|
2015-03-11 22:49:11 +00:00
|
|
|
func newGenericBackend(map[string]string) (LogicalBackend, error) {
|
2015-03-06 00:35:09 +00:00
|
|
|
b := &GenericBackend{}
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// HandleRequest is used to handle a request and generate a response.
|
|
|
|
// The backends must check the operation type and handle appropriately.
|
2015-03-11 22:49:11 +00:00
|
|
|
func (g *GenericBackend) HandleRequest(req *Request) (*Response, error) {
|
2015-03-06 00:35:09 +00:00
|
|
|
switch req.Operation {
|
2015-03-11 22:49:11 +00:00
|
|
|
case ReadOperation:
|
2015-03-06 00:35:09 +00:00
|
|
|
return g.handleRead(req)
|
2015-03-11 22:49:11 +00:00
|
|
|
case WriteOperation:
|
2015-03-06 00:35:09 +00:00
|
|
|
return g.handleWrite(req)
|
2015-03-11 22:49:11 +00:00
|
|
|
case ListOperation:
|
2015-03-06 00:35:09 +00:00
|
|
|
return g.handleList(req)
|
2015-03-11 22:49:11 +00:00
|
|
|
case DeleteOperation:
|
2015-03-06 00:35:09 +00:00
|
|
|
return g.handleDelete(req)
|
2015-03-11 22:49:11 +00:00
|
|
|
case HelpOperation:
|
2015-03-06 00:35:09 +00:00
|
|
|
return g.handleHelp(req)
|
|
|
|
default:
|
2015-03-11 22:49:11 +00:00
|
|
|
return nil, ErrUnsupportedOperation
|
2015-03-06 00:35:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// RootPaths is a list of paths that require root level privileges,
|
|
|
|
// which do not exist for the geneirc backend.
|
|
|
|
func (g *GenericBackend) RootPaths() []string {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:49:11 +00:00
|
|
|
func (g *GenericBackend) handleRead(req *Request) (*Response, error) {
|
2015-03-06 00:35:09 +00:00
|
|
|
// Read the path
|
|
|
|
out, err := req.View.Get(req.Path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("read failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fast-path the no data case
|
|
|
|
if out == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decode the data
|
|
|
|
var raw map[string]interface{}
|
|
|
|
if err := json.Unmarshal(out.Value, &raw); err != nil {
|
|
|
|
return nil, fmt.Errorf("json decoding failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if there is a lease key
|
|
|
|
leaseVal, ok := raw["lease"].(string)
|
2015-03-11 22:49:11 +00:00
|
|
|
var lease *Lease
|
2015-03-06 00:35:09 +00:00
|
|
|
if ok {
|
|
|
|
leaseDuration, err := time.ParseDuration(leaseVal)
|
|
|
|
if err == nil {
|
2015-03-11 22:49:11 +00:00
|
|
|
lease = &Lease{
|
2015-03-06 00:35:09 +00:00
|
|
|
Renewable: false,
|
|
|
|
Revokable: false,
|
|
|
|
Duration: leaseDuration,
|
|
|
|
MaxDuration: leaseDuration,
|
|
|
|
MaxIncrement: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate the response
|
2015-03-11 22:49:11 +00:00
|
|
|
resp := &Response{
|
2015-03-06 00:35:09 +00:00
|
|
|
IsSecret: true,
|
|
|
|
Lease: lease,
|
|
|
|
Data: raw,
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:49:11 +00:00
|
|
|
func (g *GenericBackend) handleWrite(req *Request) (*Response, error) {
|
2015-03-06 00:35:09 +00:00
|
|
|
// Check that some fields are given
|
|
|
|
if len(req.Data) == 0 {
|
|
|
|
return nil, fmt.Errorf("missing data fields")
|
|
|
|
}
|
|
|
|
|
|
|
|
// JSON encode the data
|
|
|
|
buf, err := json.Marshal(req.Data)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("json encoding failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write out a new key
|
2015-03-11 22:49:11 +00:00
|
|
|
entry := &Entry{
|
2015-03-06 00:35:09 +00:00
|
|
|
Key: req.Path,
|
|
|
|
Value: buf,
|
|
|
|
}
|
|
|
|
if err := req.View.Put(entry); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to write: %v", err)
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:49:11 +00:00
|
|
|
func (g *GenericBackend) handleDelete(req *Request) (*Response, error) {
|
2015-03-06 00:35:09 +00:00
|
|
|
// Delete the key at the request path
|
|
|
|
if err := req.View.Delete(req.Path); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:49:11 +00:00
|
|
|
func (g *GenericBackend) handleList(req *Request) (*Response, error) {
|
2015-03-06 00:35:09 +00:00
|
|
|
// List the keys at the prefix given by the request
|
|
|
|
keys, err := req.View.List(req.Path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate the response
|
2015-03-11 22:49:11 +00:00
|
|
|
resp := &Response{
|
2015-03-06 00:35:09 +00:00
|
|
|
IsSecret: false,
|
|
|
|
Lease: nil,
|
|
|
|
Data: map[string]interface{}{
|
|
|
|
"keys": keys,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:49:11 +00:00
|
|
|
func (g *GenericBackend) handleHelp(req *Request) (*Response, error) {
|
|
|
|
resp := &Response{
|
2015-03-06 00:35:09 +00:00
|
|
|
IsSecret: false,
|
|
|
|
Lease: nil,
|
|
|
|
Data: map[string]interface{}{
|
|
|
|
"help": genericHelpText,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// genericHelpText is the help information we return
|
|
|
|
const genericHelpText = "Generic backend for storing and retreiving raw keys with user-defined fields"
|