// 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 }