logical/framework: auto-extend leases if requested

This commit is contained in:
Mitchell Hashimoto 2015-03-21 16:20:30 +01:00
parent 05246433bb
commit 27d33ad9f7
3 changed files with 96 additions and 18 deletions

View file

@ -181,25 +181,15 @@ func (b *Backend) handleRevokeRenew(
return nil, fmt.Errorf("secret is unsupported by this backend")
}
var fn OperationFunc
switch req.Operation {
case logical.RenewOperation:
fn = secret.Renew
return secret.HandleRenew(req)
case logical.RevokeOperation:
fn = secret.Revoke
return secret.HandleRevoke(req)
default:
return nil, fmt.Errorf(
"invalid operation for revoke/renew: %s", req.Operation)
}
if fn == nil {
return nil, logical.ErrUnsupportedOperation
}
return fn(req, &FieldData{
Raw: req.Data,
Schema: secret.Fields,
})
}
func (b *Backend) handleRollback(

View file

@ -162,6 +162,30 @@ func TestBackendHandleRequest_renew(t *testing.T) {
}
}
func TestBackendHandleRequest_renewExtend(t *testing.T) {
secret := &Secret{
Type: "foo",
RenewExtend: true,
DefaultDuration: 5 * time.Second,
}
b := &Backend{
Secrets: []*Secret{secret},
}
req := logical.RenewRequest("/foo", secret.Response(nil, nil).Secret, nil)
req.Secret.LeaseIncrement = 1 * time.Hour
resp, err := b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp == nil || resp.Secret == nil {
t.Fatal("should have secret")
}
if resp.Secret.Lease != 1*time.Hour {
t.Fatalf("bad: %#v", resp.Secret)
}
}
func TestBackendHandleRequest_revoke(t *testing.T) {
var called uint32
callback := func(*logical.Request, *FieldData) (*logical.Response, error) {

View file

@ -25,15 +25,26 @@ type Secret struct {
DefaultDuration time.Duration
DefaultGracePeriod time.Duration
// Below are the operations that can be called on the secret.
// Renew is the callback called to renew this secret. If Renew is
// not specified and RenewExtend is false, then Renewable is set to
// false in the secret.
//
// Renew, if not set, will mark the secret as not renewable.
//
// Revoke is required.
Renew OperationFunc
// RenewExtend, if true, will automatically extend the lease of this
// secret type. You can specify RenewExtendMax to specify the max
// duration it can be extended, otherwise it will be extended potentially
// indefinitely.
Renew OperationFunc
RenewExtend bool
RenewExtendMax time.Duration
// Revoke is the callback called to revoke this secret. This is required.
Revoke OperationFunc
}
func (s *Secret) Renewable() bool {
return s.Renew != nil || s.RenewExtend
}
func (s *Secret) Response(
data, internal map[string]interface{}) *logical.Response {
internalData := make(map[string]interface{})
@ -44,7 +55,7 @@ func (s *Secret) Response(
return &logical.Response{
Secret: &logical.Secret{
Renewable: s.Renew != nil,
Renewable: s.Renewable(),
Lease: s.DefaultDuration,
LeaseGracePeriod: s.DefaultGracePeriod,
InternalData: internalData,
@ -53,3 +64,56 @@ func (s *Secret) Response(
Data: data,
}
}
// HandleRenew is the request handler for renewing this secret.
func (s *Secret) HandleRenew(req *logical.Request) (*logical.Response, error) {
if !s.Renewable() {
return nil, logical.ErrUnsupportedOperation
}
data := &FieldData{
Raw: req.Data,
Schema: s.Fields,
}
// If we have a callback, we just call that and that does all the logic.
if s.Renew != nil {
return s.Renew(req, data)
}
// If we're using RenewExtend, then just automaticaly extend.
if s.RenewExtend {
return s.HandleRenewExtend(req, data)
}
return nil, logical.ErrUnsupportedOperation
}
// HandleRenewExtend is the OperationFunc that just extends the lease
// of the secret.
func (s *Secret) HandleRenewExtend(
req *logical.Request, data *FieldData) (*logical.Response, error) {
// First copy the original secret/data
var resp logical.Response
resp.Secret = req.Secret
resp.Data = req.Data
// Now extend the lease by the amount specified.
resp.Secret.Lease = req.Secret.LeaseIncrement
return &resp, nil
}
// HandleRevoke is the request handler for renewing this secret.
func (s *Secret) HandleRevoke(req *logical.Request) (*logical.Response, error) {
data := &FieldData{
Raw: req.Data,
Schema: s.Fields,
}
if s.Revoke != nil {
return s.Revoke(req, data)
}
return nil, logical.ErrUnsupportedOperation
}