open-vault/sdk/framework/lease.go

129 lines
3.5 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package framework
import (
"context"
"fmt"
"strings"
"time"
"github.com/hashicorp/vault/sdk/logical"
)
// LeaseExtend is left for backwards compatibility for plugins. This function
// now just passes back the data that was passed into it to be processed in core.
// DEPRECATED
func LeaseExtend(backendIncrement, backendMax time.Duration, systemView logical.SystemView) OperationFunc {
return func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
switch {
case req.Auth != nil:
req.Auth.TTL = backendIncrement
req.Auth.MaxTTL = backendMax
return &logical.Response{Auth: req.Auth}, nil
case req.Secret != nil:
req.Secret.TTL = backendIncrement
req.Secret.MaxTTL = backendMax
return &logical.Response{Secret: req.Secret}, nil
}
return nil, fmt.Errorf("no lease options for request")
}
}
// CalculateTTL takes all the user-specified, backend, and system inputs and calculates
// a TTL for a lease
func CalculateTTL(sysView logical.SystemView, increment, backendTTL, period, backendMaxTTL, explicitMaxTTL time.Duration, startTime time.Time) (ttl time.Duration, warnings []string, errors error) {
// Truncate all times to the second since that is the lowest precision for
// TTLs
now := time.Now().Truncate(time.Second)
if startTime.IsZero() {
startTime = now
} else {
startTime = startTime.Truncate(time.Second)
}
// Use the mount's configured max unless the backend specifies
// something more restrictive (perhaps from a role configuration
// parameter)
maxTTL := sysView.MaxLeaseTTL()
if backendMaxTTL > 0 && backendMaxTTL < maxTTL {
maxTTL = backendMaxTTL
}
if explicitMaxTTL > 0 && explicitMaxTTL < maxTTL {
maxTTL = explicitMaxTTL
}
// Should never happen, but guard anyways
if maxTTL <= 0 {
return 0, nil, fmt.Errorf("max TTL must be greater than zero")
}
var maxValidTime time.Time
switch {
case period > 0:
// Cap the period value to the sys max_ttl value
if period > maxTTL {
warnings = append(warnings,
fmt.Sprintf("period of %q exceeded the effective max_ttl of %q; period value is capped accordingly",
humanDuration(period), humanDuration(maxTTL)))
period = maxTTL
}
ttl = period
if explicitMaxTTL > 0 {
maxValidTime = startTime.Add(explicitMaxTTL)
}
default:
switch {
case increment > 0:
ttl = increment
case backendTTL > 0:
ttl = backendTTL
default:
ttl = sysView.DefaultLeaseTTL()
}
// We cannot go past this time
maxValidTime = startTime.Add(maxTTL)
}
if !maxValidTime.IsZero() {
// Determine the max valid TTL
maxValidTTL := maxValidTime.Sub(now)
// If we are past the max TTL, we shouldn't be in this function...but
// fast path out if we are
if maxValidTTL <= 0 {
return 0, nil, fmt.Errorf("past the max TTL, cannot renew")
}
// If the proposed expiration is after the maximum TTL of the lease,
// cap the increment to whatever is left
if maxValidTTL-ttl < 0 {
warnings = append(warnings,
fmt.Sprintf("TTL of %q exceeded the effective max_ttl of %q; TTL value is capped accordingly",
humanDuration(ttl), humanDuration(maxValidTTL)))
ttl = maxValidTTL
}
}
return ttl, warnings, nil
}
// humanDuration prints the time duration without zero elements.
func humanDuration(d time.Duration) string {
if d == 0 {
return "0s"
}
s := d.String()
if strings.HasSuffix(s, "m0s") {
s = s[:len(s)-2]
}
if idx := strings.Index(s, "h0m"); idx > 0 {
s = s[:idx+1] + s[idx+3:]
}
return s
}