diff --git a/audit/hashstructure_test.go b/audit/hashstructure_test.go index f42fa50402..05c9c289bf 100644 --- a/audit/hashstructure_test.go +++ b/audit/hashstructure_test.go @@ -19,8 +19,7 @@ func TestCopy_auth(t *testing.T) { // Make a non-pointer one so that it can't be modified directly expected := logical.Auth{ LeaseOptions: logical.LeaseOptions{ - TTL: 1 * time.Hour, - IssueTime: time.Now(), + TTL: 1 * time.Hour, }, ClientToken: "foo", @@ -183,16 +182,14 @@ func TestHash(t *testing.T) { { &logical.Auth{ LeaseOptions: logical.LeaseOptions{ - TTL: 1 * time.Hour, - IssueTime: now, + TTL: 1 * time.Hour, }, ClientToken: "foo", }, &logical.Auth{ LeaseOptions: logical.LeaseOptions{ - TTL: 1 * time.Hour, - IssueTime: now, + TTL: 1 * time.Hour, }, ClientToken: "hmac-sha256:08ba357e274f528065766c770a639abf6809b39ccfd37c2a3157c7f51954da0a", diff --git a/builtin/credential/app-id/path_login.go b/builtin/credential/app-id/path_login.go index 76ea028088..584fe4ea9e 100644 --- a/builtin/credential/app-id/path_login.go +++ b/builtin/credential/app-id/path_login.go @@ -146,7 +146,7 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *f return nil, fmt.Errorf("policies do not match") } - return framework.LeaseExtend(0, 0, b.System())(ctx, req, d) + return &logical.Response{Auth: req.Auth}, nil } func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, appId, userId string) (string, *logical.Response, error) { diff --git a/builtin/credential/approle/path_login.go b/builtin/credential/approle/path_login.go index 820fdb67d7..8ea6132882 100644 --- a/builtin/credential/approle/path_login.go +++ b/builtin/credential/approle/path_login.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "strings" - "time" "github.com/hashicorp/errwrap" "github.com/hashicorp/vault/logical" @@ -107,17 +106,11 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, data return nil, fmt.Errorf("role %s does not exist during renewal", roleName) } - // If a period is provided, set that as part of resp.Auth.Period and return a - // response immediately. Let expiration manager handle renewal from there on. - if role.Period > time.Duration(0) { - resp := &logical.Response{ - Auth: req.Auth, - } - resp.Auth.Period = role.Period - return resp, nil - } - - return framework.LeaseExtend(role.TokenTTL, role.TokenMaxTTL, b.System())(ctx, req, data) + resp := &logical.Response{Auth: req.Auth} + resp.Auth.TTL = role.TokenTTL + resp.Auth.MaxTTL = role.TokenMaxTTL + resp.Auth.Period = role.Period + return resp, nil } const pathLoginHelpSys = "Issue a token based on the credentials supplied" diff --git a/builtin/credential/approle/path_login_test.go b/builtin/credential/approle/path_login_test.go index 44d2ec2c0c..b5f5cbf6c2 100644 --- a/builtin/credential/approle/path_login_test.go +++ b/builtin/credential/approle/path_login_test.go @@ -147,7 +147,6 @@ func generateRenewRequest(s logical.Storage, auth *logical.Auth) *logical.Reques renewReq.Auth.Metadata = auth.Metadata renewReq.Auth.LeaseOptions = auth.LeaseOptions renewReq.Auth.Policies = auth.Policies - renewReq.Auth.IssueTime = time.Now() renewReq.Auth.Period = auth.Period return renewReq diff --git a/builtin/credential/approle/validation.go b/builtin/credential/approle/validation.go index 5ec11097d6..475692983b 100644 --- a/builtin/credential/approle/validation.go +++ b/builtin/credential/approle/validation.go @@ -112,11 +112,6 @@ func (b *backend) validateCredentials(ctx context.Context, req *logical.Request, return nil, "", metadata, "", fmt.Errorf("failed to validate role_id"), nil } - // Calculate the TTL boundaries since this reflects the properties of the token issued - if role.TokenTTL, role.TokenMaxTTL, err = b.SanitizeTTL(role.TokenTTL, role.TokenMaxTTL); err != nil { - return nil, "", metadata, "", nil, err - } - var secretID string if role.BindSecretID { // If 'bind_secret_id' was set on role, look for the field 'secret_id' diff --git a/builtin/credential/aws/backend_test.go b/builtin/credential/aws/backend_test.go index df0d5b5146..64b16a300d 100644 --- a/builtin/credential/aws/backend_test.go +++ b/builtin/credential/aws/backend_test.go @@ -1733,7 +1733,6 @@ func generateRenewRequest(s logical.Storage, auth *logical.Auth) *logical.Reques renewReq.Auth.Metadata = auth.Metadata renewReq.Auth.LeaseOptions = auth.LeaseOptions renewReq.Auth.Policies = auth.Policies - renewReq.Auth.IssueTime = time.Now() renewReq.Auth.Period = auth.Period return renewReq diff --git a/builtin/credential/aws/path_login.go b/builtin/credential/aws/path_login.go index 6bd0291799..6bad35de7f 100644 --- a/builtin/credential/aws/path_login.go +++ b/builtin/credential/aws/path_login.go @@ -809,6 +809,7 @@ func (b *backend) pathLoginUpdateEc2(ctx context.Context, req *logical.Request, LeaseOptions: logical.LeaseOptions{ Renewable: true, TTL: roleEntry.TTL, + MaxTTL: shortestMaxTTL, }, Alias: &logical.Alias{ Name: identityDocParsed.InstanceID, @@ -826,16 +827,6 @@ func (b *backend) pathLoginUpdateEc2(ctx context.Context, req *logical.Request, resp.Auth.Metadata["nonce"] = clientNonce } - // In this case no role value was set so pull in what will be assigned by - // Core for comparison - if resp.Auth.TTL == 0 { - resp.Auth.TTL = b.System().DefaultLeaseTTL() - } - if resp.Auth.TTL > shortestMaxTTL { - resp.Auth.TTL = shortestMaxTTL - resp.AddWarning(fmt.Sprintf("Effective TTL of '%s' exceeded the effective max_ttl of '%s'; TTL value is capped accordingly", resp.Auth.TTL, shortestMaxTTL)) - } - return resp, nil } @@ -1025,17 +1016,11 @@ func (b *backend) pathLoginRenewIam(ctx context.Context, req *logical.Request, d } } - // If a period is provided, set that as part of resp.Auth.Period and return a - // response immediately. Let expiration manager handle renewal from there on. - if roleEntry.Period > time.Duration(0) { - resp := &logical.Response{ - Auth: req.Auth, - } - resp.Auth.Period = roleEntry.Period - return resp, nil - } - - return framework.LeaseExtend(roleEntry.TTL, roleEntry.MaxTTL, b.System())(ctx, req, data) + resp := &logical.Response{Auth: req.Auth} + resp.Auth.TTL = roleEntry.TTL + resp.Auth.MaxTTL = roleEntry.MaxTTL + resp.Auth.Period = roleEntry.Period + return resp, nil } func (b *backend) pathLoginRenewEc2(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { @@ -1115,17 +1100,11 @@ func (b *backend) pathLoginRenewEc2(ctx context.Context, req *logical.Request, d return nil, err } - // If a period is provided, set that as part of resp.Auth.Period and return a - // response immediately. Let expiration manager handle renewal from there on. - if roleEntry.Period > time.Duration(0) { - resp := &logical.Response{ - Auth: req.Auth, - } - resp.Auth.Period = roleEntry.Period - return resp, nil - } - - return framework.LeaseExtend(roleEntry.TTL, shortestMaxTTL, b.System())(ctx, req, data) + resp := &logical.Response{Auth: req.Auth} + resp.Auth.TTL = roleEntry.TTL + resp.Auth.MaxTTL = shortestMaxTTL + resp.Auth.Period = roleEntry.Period + return resp, nil } func (b *backend) pathLoginUpdateIam(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { diff --git a/builtin/credential/cert/backend_test.go b/builtin/credential/cert/backend_test.go index 2f9b5c379e..ec1c831394 100644 --- a/builtin/credential/cert/backend_test.go +++ b/builtin/credential/cert/backend_test.go @@ -1416,7 +1416,6 @@ func Test_Renew(t *testing.T) { req.Auth.Metadata = resp.Auth.Metadata req.Auth.LeaseOptions = resp.Auth.LeaseOptions req.Auth.Policies = resp.Auth.Policies - req.Auth.IssueTime = time.Now() req.Auth.Period = resp.Auth.Period // Normal renewal diff --git a/builtin/credential/cert/path_login.go b/builtin/credential/cert/path_login.go index 912332f07f..65e06b987b 100644 --- a/builtin/credential/cert/path_login.go +++ b/builtin/credential/cert/path_login.go @@ -11,7 +11,6 @@ import ( "errors" "fmt" "strings" - "time" "github.com/hashicorp/vault/helper/certutil" "github.com/hashicorp/vault/helper/policyutil" @@ -72,11 +71,6 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, data *fra return nil, nil } - ttl := matched.Entry.TTL - if ttl == 0 { - ttl = b.System().DefaultLeaseTTL() - } - clientCerts := req.Connection.ConnState.PeerCertificates if len(clientCerts) == 0 { return logical.ErrorResponse("no client certificate found"), nil @@ -101,7 +95,8 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, data *fra }, LeaseOptions: logical.LeaseOptions{ Renewable: true, - TTL: ttl, + TTL: matched.Entry.TTL, + MaxTTL: matched.Entry.MaxTTL, }, Alias: &logical.Alias{ Name: clientCerts[0].SerialNumber.String(), @@ -109,20 +104,6 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, data *fra }, } - if matched.Entry.MaxTTL > time.Duration(0) { - // Cap maxTTL to the sysview's max TTL - maxTTL := matched.Entry.MaxTTL - if maxTTL > b.System().MaxLeaseTTL() { - maxTTL = b.System().MaxLeaseTTL() - } - - // Cap TTL to MaxTTL - if resp.Auth.TTL > maxTTL { - resp.AddWarning(fmt.Sprintf("Effective TTL of '%s' exceeded the effective max_ttl of '%s'; TTL value is capped accordingly", (resp.Auth.TTL / time.Second), (maxTTL / time.Second))) - resp.Auth.TTL = maxTTL - } - } - // Generate a response return resp, nil } @@ -175,17 +156,11 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *f return nil, fmt.Errorf("policies have changed, not renewing") } - // If a period is provided, set that as part of resp.Auth.Period and return a - // response immediately. Let expiration manager handle renewal from there on. - if cert.Period > time.Duration(0) { - resp := &logical.Response{ - Auth: req.Auth, - } - resp.Auth.Period = cert.Period - return resp, nil - } - - return framework.LeaseExtend(cert.TTL, cert.MaxTTL, b.System())(ctx, req, d) + resp := &logical.Response{Auth: req.Auth} + resp.Auth.TTL = cert.TTL + resp.Auth.MaxTTL = cert.MaxTTL + resp.Auth.Period = cert.Period + return resp, nil } func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, d *framework.FieldData) (*ParsedCert, *logical.Response, error) { diff --git a/builtin/credential/github/path_login.go b/builtin/credential/github/path_login.go index 40b1844d04..07af427851 100644 --- a/builtin/credential/github/path_login.go +++ b/builtin/credential/github/path_login.go @@ -67,7 +67,7 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, data *fra return nil, err } - ttl, _, err := b.SanitizeTTLStr(config.TTL.String(), config.MaxTTL.String()) + ttl, maxTTL, err := b.SanitizeTTLStr(config.TTL.String(), config.MaxTTL.String()) if err != nil { return logical.ErrorResponse(fmt.Sprintf("error sanitizing TTLs: %s", err)), nil } @@ -85,6 +85,7 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, data *fra DisplayName: *verifyResp.User.Login, LeaseOptions: logical.LeaseOptions{ TTL: ttl, + MaxTTL: maxTTL, Renewable: true, }, Alias: &logical.Alias{ @@ -133,10 +134,9 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *f return nil, err } - resp, err := framework.LeaseExtend(config.TTL, config.MaxTTL, b.System())(ctx, req, d) - if err != nil { - return nil, err - } + resp := &logical.Response{Auth: req.Auth} + resp.Auth.TTL = config.TTL + resp.Auth.MaxTTL = config.MaxTTL // Remove old aliases resp.Auth.GroupAliases = nil diff --git a/builtin/credential/ldap/path_login.go b/builtin/credential/ldap/path_login.go index 7b04602046..1950df1d66 100644 --- a/builtin/credential/ldap/path_login.go +++ b/builtin/credential/ldap/path_login.go @@ -111,10 +111,7 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *f return nil, fmt.Errorf("policies have changed, not renewing") } - resp, err = framework.LeaseExtend(0, 0, b.System())(ctx, req, d) - if err != nil { - return nil, err - } + resp.Auth = req.Auth // Remove old aliases resp.Auth.GroupAliases = nil diff --git a/builtin/credential/okta/path_login.go b/builtin/credential/okta/path_login.go index a7a719e242..9b6e7dfeb1 100644 --- a/builtin/credential/okta/path_login.go +++ b/builtin/credential/okta/path_login.go @@ -89,6 +89,7 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, d *framew DisplayName: username, LeaseOptions: logical.LeaseOptions{ TTL: cfg.TTL, + MaxTTL: cfg.MaxTTL, Renewable: true, }, Alias: &logical.Alias{ @@ -96,21 +97,6 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, d *framew }, } - if resp.Auth.TTL == 0 { - resp.Auth.TTL = b.System().DefaultLeaseTTL() - } - if cfg.MaxTTL > 0 { - maxTTL := cfg.MaxTTL - if maxTTL > b.System().MaxLeaseTTL() { - maxTTL = b.System().MaxLeaseTTL() - } - - if resp.Auth.TTL > maxTTL { - resp.Auth.TTL = maxTTL - resp.AddWarning(fmt.Sprintf("Effective TTL of '%s' exceeded the effective max_ttl of '%s'; TTL value is capped accordingly", resp.Auth.TTL, maxTTL)) - } - } - for _, groupName := range groupNames { if groupName == "" { continue @@ -141,10 +127,9 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *f return nil, err } - resp, err = framework.LeaseExtend(cfg.TTL, cfg.MaxTTL, b.System())(ctx, req, d) - if err != nil { - return nil, err - } + resp.Auth = req.Auth + resp.Auth.TTL = cfg.TTL + resp.Auth.MaxTTL = cfg.MaxTTL // Remove old aliases resp.Auth.GroupAliases = nil diff --git a/builtin/credential/radius/path_login.go b/builtin/credential/radius/path_login.go index 4ea0d6f589..6779c00e68 100644 --- a/builtin/credential/radius/path_login.go +++ b/builtin/credential/radius/path_login.go @@ -88,6 +88,7 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, d *framew } } + resp.Auth = req.Auth resp.Auth = &logical.Auth{ Policies: policies, Metadata: map[string]string{ @@ -126,7 +127,7 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *f return nil, fmt.Errorf("policies have changed, not renewing") } - return framework.LeaseExtend(0, 0, b.System())(ctx, req, d) + return &logical.Response{Auth: req.Auth}, nil } func (b *backend) RadiusLogin(ctx context.Context, req *logical.Request, username string, password string) ([]string, *logical.Response, error) { diff --git a/builtin/credential/userpass/backend_test.go b/builtin/credential/userpass/backend_test.go index 6af9693c3f..12610d3c36 100644 --- a/builtin/credential/userpass/backend_test.go +++ b/builtin/credential/userpass/backend_test.go @@ -18,57 +18,6 @@ const ( testSysMaxTTL = time.Hour * 20 ) -func TestBackend_TTLDurations(t *testing.T) { - data1 := map[string]interface{}{ - "password": "password", - "policies": "root", - "ttl": "21h", - "max_ttl": "11h", - } - data2 := map[string]interface{}{ - "password": "password", - "policies": "root", - "ttl": "10h", - "max_ttl": "21h", - } - data3 := map[string]interface{}{ - "password": "password", - "policies": "root", - "ttl": "10h", - "max_ttl": "10h", - } - data4 := map[string]interface{}{ - "password": "password", - "policies": "root", - "ttl": "11h", - "max_ttl": "5h", - } - data5 := map[string]interface{}{ - "password": "password", - } - b, err := Factory(context.Background(), &logical.BackendConfig{ - Logger: nil, - System: &logical.StaticSystemView{ - DefaultLeaseTTLVal: testSysTTL, - MaxLeaseTTLVal: testSysMaxTTL, - }, - }) - if err != nil { - t.Fatalf("Unable to create backend: %s", err) - } - logicaltest.Test(t, logicaltest.TestCase{ - Backend: b, - Steps: []logicaltest.TestStep{ - testUsersWrite(t, "test", data1, true), - testUsersWrite(t, "test", data2, true), - testUsersWrite(t, "test", data3, false), - testUsersWrite(t, "test", data4, false), - testLoginWrite(t, "test", data5, false), - testLoginWrite(t, "wrong", data5, true), - }, - }) -} - func TestBackend_basic(t *testing.T) { b, err := Factory(context.Background(), &logical.BackendConfig{ Logger: nil, diff --git a/builtin/credential/userpass/path_login.go b/builtin/credential/userpass/path_login.go index 32b5b4035c..4164196b29 100644 --- a/builtin/credential/userpass/path_login.go +++ b/builtin/credential/userpass/path_login.go @@ -91,6 +91,7 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, d *framew DisplayName: username, LeaseOptions: logical.LeaseOptions{ TTL: user.TTL, + MaxTTL: user.MaxTTL, Renewable: true, }, Alias: &logical.Alias{ @@ -115,7 +116,10 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *f return nil, fmt.Errorf("policies have changed, not renewing") } - return framework.LeaseExtend(user.TTL, user.MaxTTL, b.System())(ctx, req, d) + resp := &logical.Response{Auth: req.Auth} + resp.Auth.TTL = user.TTL + resp.Auth.MaxTTL = user.MaxTTL + return resp, nil } const pathLoginSyn = ` diff --git a/builtin/logical/aws/secret_access_keys.go b/builtin/logical/aws/secret_access_keys.go index 552d496bca..93d2bb4dd2 100644 --- a/builtin/logical/aws/secret_access_keys.go +++ b/builtin/logical/aws/secret_access_keys.go @@ -243,6 +243,7 @@ func (b *backend) secretAccessKeysCreate( } resp.Secret.TTL = lease.Lease + resp.Secret.MaxTTL = lease.LeaseMax if usernameWarning != "" { resp.AddWarning(usernameWarning) @@ -271,8 +272,10 @@ func (b *backend) secretAccessKeysRenew(ctx context.Context, req *logical.Reques lease = &configLease{} } - f := framework.LeaseExtend(lease.Lease, lease.LeaseMax, b.System()) - return f(ctx, req, d) + resp := &logical.Response{Secret: req.Secret} + resp.Secret.TTL = lease.Lease + resp.Secret.MaxTTL = lease.LeaseMax + return resp, nil } func secretAccessKeysRevoke(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { diff --git a/builtin/logical/cassandra/secret_creds.go b/builtin/logical/cassandra/secret_creds.go index 098f4cd350..5fed475799 100644 --- a/builtin/logical/cassandra/secret_creds.go +++ b/builtin/logical/cassandra/secret_creds.go @@ -47,7 +47,9 @@ func (b *backend) secretCredsRenew(ctx context.Context, req *logical.Request, d return nil, fmt.Errorf("unable to load role: %s", err) } - return framework.LeaseExtend(role.Lease, 0, b.System())(ctx, req, d) + resp := &logical.Response{Secret: req.Secret} + resp.Secret.TTL = role.Lease + return resp, nil } func (b *backend) secretCredsRevoke(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { diff --git a/builtin/logical/consul/backend_test.go b/builtin/logical/consul/backend_test.go index a79cb15542..ce14056019 100644 --- a/builtin/logical/consul/backend_test.go +++ b/builtin/logical/consul/backend_test.go @@ -206,7 +206,6 @@ func TestBackend_renew_revoke(t *testing.T) { } generatedSecret := resp.Secret - generatedSecret.IssueTime = time.Now() generatedSecret.TTL = 6 * time.Hour var d struct { diff --git a/builtin/logical/consul/secret_token.go b/builtin/logical/consul/secret_token.go index e8256daa4a..9a8b956e97 100644 --- a/builtin/logical/consul/secret_token.go +++ b/builtin/logical/consul/secret_token.go @@ -28,14 +28,15 @@ func secretToken(b *backend) *framework.Secret { } func (b *backend) secretTokenRenew(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + resp := &logical.Response{Secret: req.Secret} roleRaw, ok := req.Secret.InternalData["role"] if !ok || roleRaw == nil { - return framework.LeaseExtend(0, 0, b.System())(ctx, req, d) + return resp, nil } role, ok := roleRaw.(string) if !ok { - return framework.LeaseExtend(0, 0, b.System())(ctx, req, d) + return resp, nil } entry, err := req.Storage.Get(ctx, "policy/"+role) @@ -50,8 +51,8 @@ func (b *backend) secretTokenRenew(ctx context.Context, req *logical.Request, d if err := entry.DecodeJSON(&result); err != nil { return nil, err } - - return framework.LeaseExtend(result.Lease, 0, b.System())(ctx, req, d) + resp.Secret.TTL = result.Lease + return resp, nil } func secretTokenRevoke(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { diff --git a/builtin/logical/database/dbplugin/database.pb.go b/builtin/logical/database/dbplugin/database.pb.go index 31ae9c5c46..06450ce55d 100644 --- a/builtin/logical/database/dbplugin/database.pb.go +++ b/builtin/logical/database/dbplugin/database.pb.go @@ -1,6 +1,5 @@ -// Code generated by protoc-gen-go. +// Code generated by protoc-gen-go. DO NOT EDIT. // source: builtin/logical/database/dbplugin/database.proto -// DO NOT EDIT! /* Package dbplugin is a generated protocol buffer package. diff --git a/builtin/logical/database/secret_creds.go b/builtin/logical/database/secret_creds.go index 754ff0e260..b6cd3ede9e 100644 --- a/builtin/logical/database/secret_creds.go +++ b/builtin/logical/database/secret_creds.go @@ -3,6 +3,7 @@ package database import ( "context" "fmt" + "time" "github.com/hashicorp/vault/logical" "github.com/hashicorp/vault/logical/framework" @@ -42,12 +43,6 @@ func (b *databaseBackend) secretCredsRenew() framework.OperationFunc { return nil, fmt.Errorf("error during renew: could not find role with name %s", req.Secret.InternalData["role"]) } - f := framework.LeaseExtend(role.DefaultTTL, role.MaxTTL, b.System()) - resp, err := f(ctx, req, data) - if err != nil { - return nil, err - } - // Get the Database object db, err := b.GetConnection(ctx, req.Storage, role.DBName) if err != nil { @@ -58,13 +53,24 @@ func (b *databaseBackend) secretCredsRenew() framework.OperationFunc { defer db.RUnlock() // Make sure we increase the VALID UNTIL endpoint for this user. - if expireTime := resp.Secret.ExpirationTime(); !expireTime.IsZero() { + ttl, _, err := framework.CalculateTTL(b.System(), req.Secret.Increment, role.DefaultTTL, 0, role.MaxTTL, 0, req.Secret.IssueTime) + if err != nil { + return nil, err + } + if ttl > 0 { + expireTime := time.Now().Add(ttl) + // Adding a small buffer since the TTL will be calculated again after this call + // to ensure the database credential does not expire before the lease + expireTime = expireTime.Add(5 * time.Second) err := db.RenewUser(ctx, role.Statements, username, expireTime) if err != nil { b.CloseIfShutdown(db, err) return nil, err } } + resp := &logical.Response{Secret: req.Secret} + resp.Secret.TTL = role.DefaultTTL + resp.Secret.MaxTTL = role.MaxTTL return resp, nil } } diff --git a/builtin/logical/mongodb/secret_creds.go b/builtin/logical/mongodb/secret_creds.go index 200c452d6f..bde31c6819 100644 --- a/builtin/logical/mongodb/secret_creds.go +++ b/builtin/logical/mongodb/secret_creds.go @@ -41,8 +41,10 @@ func (b *backend) secretCredsRenew(ctx context.Context, req *logical.Request, d leaseConfig = &configLease{} } - f := framework.LeaseExtend(leaseConfig.TTL, leaseConfig.MaxTTL, b.System()) - return f(ctx, req, d) + resp := &logical.Response{Secret: req.Secret} + resp.Secret.TTL = leaseConfig.TTL + resp.Secret.MaxTTL = leaseConfig.MaxTTL + return resp, nil } func (b *backend) secretCredsRevoke(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { diff --git a/builtin/logical/mssql/secret_creds.go b/builtin/logical/mssql/secret_creds.go index 4731c0751a..8ff8d2a84e 100644 --- a/builtin/logical/mssql/secret_creds.go +++ b/builtin/logical/mssql/secret_creds.go @@ -41,8 +41,10 @@ func (b *backend) secretCredsRenew(ctx context.Context, req *logical.Request, d leaseConfig = &configLease{} } - f := framework.LeaseExtend(leaseConfig.TTL, leaseConfig.TTLMax, b.System()) - return f(ctx, req, d) + resp := &logical.Response{Secret: req.Secret} + resp.Secret.TTL = leaseConfig.TTL + resp.Secret.MaxTTL = leaseConfig.TTLMax + return resp, nil } func (b *backend) secretCredsRevoke(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { diff --git a/builtin/logical/mysql/path_role_create.go b/builtin/logical/mysql/path_role_create.go index 2b216ccf8c..ae184bdb34 100644 --- a/builtin/logical/mysql/path_role_create.go +++ b/builtin/logical/mysql/path_role_create.go @@ -130,11 +130,8 @@ func (b *backend) pathRoleCreateRead(ctx context.Context, req *logical.Request, "role": name, }) - ttl := lease.Lease - if ttl == 0 || (lease.LeaseMax > 0 && ttl > lease.LeaseMax) { - ttl = lease.LeaseMax - } - resp.Secret.TTL = ttl + resp.Secret.TTL = lease.Lease + resp.Secret.MaxTTL = lease.LeaseMax return resp, nil } diff --git a/builtin/logical/mysql/secret_creds.go b/builtin/logical/mysql/secret_creds.go index a53cf29f49..65d59dbc40 100644 --- a/builtin/logical/mysql/secret_creds.go +++ b/builtin/logical/mysql/secret_creds.go @@ -52,8 +52,10 @@ func (b *backend) secretCredsRenew(ctx context.Context, req *logical.Request, d lease = &configLease{} } - f := framework.LeaseExtend(lease.Lease, lease.LeaseMax, b.System()) - return f(ctx, req, d) + resp := &logical.Response{Secret: req.Secret} + resp.Secret.TTL = lease.Lease + resp.Secret.MaxTTL = lease.LeaseMax + return resp, nil } func (b *backend) secretCredsRevoke(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { diff --git a/builtin/logical/nomad/backend_test.go b/builtin/logical/nomad/backend_test.go index 0eb45853d3..9f03d63794 100644 --- a/builtin/logical/nomad/backend_test.go +++ b/builtin/logical/nomad/backend_test.go @@ -202,7 +202,6 @@ func TestBackend_renew_revoke(t *testing.T) { } generatedSecret := resp.Secret - generatedSecret.IssueTime = time.Now() generatedSecret.TTL = 6 * time.Hour var d struct { diff --git a/builtin/logical/nomad/path_creds_create.go b/builtin/logical/nomad/path_creds_create.go index 4d68f017fb..43922b45b0 100644 --- a/builtin/logical/nomad/path_creds_create.go +++ b/builtin/logical/nomad/path_creds_create.go @@ -81,6 +81,7 @@ func (b *backend) pathTokenRead(ctx context.Context, req *logical.Request, d *fr "accessor_id": token.AccessorID, }) resp.Secret.TTL = leaseConfig.TTL + resp.Secret.MaxTTL = leaseConfig.MaxTTL return resp, nil } diff --git a/builtin/logical/nomad/secret_token.go b/builtin/logical/nomad/secret_token.go index 3e8661bea7..3509dcba48 100644 --- a/builtin/logical/nomad/secret_token.go +++ b/builtin/logical/nomad/secret_token.go @@ -36,8 +36,10 @@ func (b *backend) secretTokenRenew(ctx context.Context, req *logical.Request, d if lease == nil { lease = &configLease{} } - - return framework.LeaseExtend(lease.TTL, lease.MaxTTL, b.System())(ctx, req, d) + resp := &logical.Response{Secret: req.Secret} + resp.Secret.TTL = lease.TTL + resp.Secret.MaxTTL = lease.MaxTTL + return resp, nil } func (b *backend) secretTokenRevoke(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { diff --git a/builtin/logical/postgresql/secret_creds.go b/builtin/logical/postgresql/secret_creds.go index 570883e258..95b291af7a 100644 --- a/builtin/logical/postgresql/secret_creds.go +++ b/builtin/logical/postgresql/secret_creds.go @@ -5,6 +5,7 @@ import ( "database/sql" "fmt" "strings" + "time" "github.com/hashicorp/vault/helper/strutil" "github.com/hashicorp/vault/logical" @@ -59,14 +60,16 @@ func (b *backend) secretCredsRenew(ctx context.Context, req *logical.Request, d lease = &configLease{} } - f := framework.LeaseExtend(lease.Lease, lease.LeaseMax, b.System()) - resp, err := f(ctx, req, d) + // Make sure we increase the VALID UNTIL endpoint for this user. + ttl, _, err := framework.CalculateTTL(b.System(), req.Secret.Increment, lease.Lease, 0, lease.LeaseMax, 0, req.Secret.IssueTime) if err != nil { return nil, err } - - // Make sure we increase the VALID UNTIL endpoint for this user. - if expireTime := resp.Secret.ExpirationTime(); !expireTime.IsZero() { + if ttl > 0 { + expireTime := time.Now().Add(ttl) + // Adding a small buffer since the TTL will be calculated again afeter this call + // to ensure the database credential does not expire before the lease + expireTime = expireTime.Add(5 * time.Second) expiration := expireTime.Format("2006-01-02 15:04:05-0700") query := fmt.Sprintf( @@ -83,6 +86,9 @@ func (b *backend) secretCredsRenew(ctx context.Context, req *logical.Request, d } } + resp := &logical.Response{Secret: req.Secret} + resp.Secret.TTL = lease.Lease + resp.Secret.MaxTTL = lease.LeaseMax return resp, nil } diff --git a/builtin/logical/rabbitmq/path_role_create.go b/builtin/logical/rabbitmq/path_role_create.go index 7d83f63130..5cb015c469 100644 --- a/builtin/logical/rabbitmq/path_role_create.go +++ b/builtin/logical/rabbitmq/path_role_create.go @@ -105,11 +105,8 @@ func (b *backend) pathCredsRead(ctx context.Context, req *logical.Request, d *fr } if lease != nil { - ttl := lease.TTL - if ttl == 0 || (lease.MaxTTL > 0 && ttl > lease.MaxTTL) { - ttl = lease.MaxTTL - } - resp.Secret.TTL = ttl + resp.Secret.TTL = lease.TTL + resp.Secret.MaxTTL = lease.MaxTTL } return resp, nil diff --git a/builtin/logical/rabbitmq/secret_creds.go b/builtin/logical/rabbitmq/secret_creds.go index df336720a6..cb7e977ebc 100644 --- a/builtin/logical/rabbitmq/secret_creds.go +++ b/builtin/logical/rabbitmq/secret_creds.go @@ -40,7 +40,10 @@ func (b *backend) secretCredsRenew(ctx context.Context, req *logical.Request, d lease = &configLease{} } - return framework.LeaseExtend(lease.TTL, lease.MaxTTL, b.System())(ctx, req, d) + resp := &logical.Response{Secret: req.Secret} + resp.Secret.TTL = lease.TTL + resp.Secret.MaxTTL = lease.MaxTTL + return resp, nil } // Revoke the previously issued secret diff --git a/builtin/logical/ssh/secret_dynamic_key.go b/builtin/logical/ssh/secret_dynamic_key.go index fd85ac0950..1a0b3eefb4 100644 --- a/builtin/logical/ssh/secret_dynamic_key.go +++ b/builtin/logical/ssh/secret_dynamic_key.go @@ -32,8 +32,7 @@ func secretDynamicKey(b *backend) *framework.Secret { } func (b *backend) secretDynamicKeyRenew(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { - f := framework.LeaseExtend(0, 0, b.System()) - return f(ctx, req, d) + return &logical.Response{Secret: req.Secret}, nil } func (b *backend) secretDynamicKeyRevoke(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { diff --git a/http/auth_token_test.go b/http/auth_token_test.go index 9822f7d122..6cc1850fe3 100644 --- a/http/auth_token_test.go +++ b/http/auth_token_test.go @@ -70,7 +70,7 @@ func TestAuthTokenCreate(t *testing.T) { t.Fatal(err) } if secret.Auth.LeaseDuration != 1800 { - t.Errorf("expected 1800 seconds, got %q", secret.Auth.LeaseDuration) + t.Errorf("expected 1800 seconds, got %d", secret.Auth.LeaseDuration) } explicitMaxCreateRequest.ExplicitMaxTTL = "2h" diff --git a/logical/auth.go b/logical/auth.go index f5310149bc..2012418ad5 100644 --- a/logical/auth.go +++ b/logical/auth.go @@ -49,6 +49,10 @@ type Auth struct { // specified by this period. Period time.Duration `json:"period" mapstructure:"period" structs:"period"` + // ExplicitMaxTTL is the max TTL that constrains periodic tokens. For normal + // tokens, this value is constrained by the configured max ttl. + ExplicitMaxTTL time.Duration `json:"-" mapstructure:"-" structs:"-"` + // Number of allowed uses of the issued token NumUses int `json:"num_uses" mapstructure:"num_uses" structs:"num_uses"` diff --git a/logical/framework/backend.go b/logical/framework/backend.go index caf8b2cccf..da7c039234 100644 --- a/logical/framework/backend.go +++ b/logical/framework/backend.go @@ -291,24 +291,6 @@ func (b *Backend) SanitizeTTLStr(ttlStr, maxTTLStr string) (ttl, maxTTL time.Dur } } - ttl, maxTTL, err = b.SanitizeTTL(ttl, maxTTL) - - return -} - -// SanitizeTTL caps the boundaries of ttl and max_ttl values to the -// backend mount's max_ttl value. -func (b *Backend) SanitizeTTL(ttl, maxTTL time.Duration) (time.Duration, time.Duration, error) { - sysMaxTTL := b.System().MaxLeaseTTL() - if ttl > sysMaxTTL { - return 0, 0, fmt.Errorf("\"ttl\" value must be less than allowed max lease TTL value '%s'", sysMaxTTL.String()) - } - if maxTTL > sysMaxTTL { - return 0, 0, fmt.Errorf("\"max_ttl\" value must be less than allowed max lease TTL value '%s'", sysMaxTTL.String()) - } - if ttl > maxTTL && maxTTL != 0 { - ttl = maxTTL - } return ttl, maxTTL, nil } diff --git a/logical/framework/backend_test.go b/logical/framework/backend_test.go index 32655faa4c..eb80889c1a 100644 --- a/logical/framework/backend_test.go +++ b/logical/framework/backend_test.go @@ -245,37 +245,6 @@ func TestBackendHandleRequest_renew(t *testing.T) { } } -func TestBackendHandleRequest_renewExtend(t *testing.T) { - sysView := logical.StaticSystemView{ - DefaultLeaseTTLVal: 5 * time.Minute, - MaxLeaseTTLVal: 30 * time.Hour, - } - - secret := &Secret{ - Type: "foo", - Renew: LeaseExtend(0, 0, sysView), - DefaultDuration: 5 * time.Minute, - } - b := &Backend{ - Secrets: []*Secret{secret}, - } - - req := logical.RenewRequest("/foo", secret.Response(nil, nil).Secret, nil) - req.Secret.IssueTime = time.Now() - req.Secret.Increment = 1 * time.Hour - resp, err := b.HandleRequest(context.Background(), req) - if err != nil { - t.Fatalf("err: %s", err) - } - if resp == nil || resp.Secret == nil { - t.Fatal("should have secret") - } - - if resp.Secret.TTL < 59*time.Minute || resp.Secret.TTL > 61*time.Minute { - t.Fatalf("bad: %s", resp.Secret.TTL) - } -} - func TestBackendHandleRequest_revoke(t *testing.T) { var called uint32 callback := func(context.Context, *logical.Request, *FieldData) (*logical.Response, error) { diff --git a/logical/framework/lease.go b/logical/framework/lease.go index 56523ff47c..4f55ae0de3 100644 --- a/logical/framework/lease.go +++ b/logical/framework/lease.go @@ -8,80 +8,99 @@ import ( "github.com/hashicorp/vault/logical" ) -// LeaseExtend returns an OperationFunc that can be used to simply extend the -// lease of the auth/secret for the duration that was requested. The parameters -// provided are used to determine the lease's new TTL value. -// -// backendIncrement is the backend's requested increment -- perhaps from a user -// request, perhaps from a role/config value. If not set, uses the mount/system -// value. -// -// backendMax is the backend's requested increment -- this can be more -// restrictive than the mount/system value but not less. -// -// systemView is the system view from the calling backend, used to determine -// and/or correct default/max times. +// 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) { - var leaseOpts *logical.LeaseOptions switch { case req.Auth != nil: - leaseOpts = &req.Auth.LeaseOptions + req.Auth.TTL = backendIncrement + req.Auth.MaxTTL = backendMax + return &logical.Response{Auth: req.Auth}, nil case req.Secret != nil: - leaseOpts = &req.Secret.LeaseOptions + 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", period, 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: - return nil, fmt.Errorf("no lease options for request") - } - - // Use the mount's configured max unless the backend specifies - // something more restrictive (perhaps from a role configuration - // parameter) - max := systemView.MaxLeaseTTL() - if backendMax > 0 && backendMax < max { - max = backendMax - } - - // Should never happen, but guard anyways - if max < 0 { - return nil, fmt.Errorf("max TTL is negative") + ttl = sysView.DefaultLeaseTTL() } // We cannot go past this time - maxValidTime := leaseOpts.IssueTime.Add(max) + maxValidTime = startTime.Add(maxTTL) + } - // Get the current time - now := time.Now() + 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 maxValidTime.Before(now) { - return nil, fmt.Errorf("past the max TTL, cannot renew") + if maxValidTTL < 0 { + return 0, nil, fmt.Errorf("past the max TTL, cannot renew") } - // Basic max safety checks have passed, now let's figure out our - // increment. We'll use the user-supplied value first, then backend-provided default if possible, or the - // mount/system default if not. - increment := leaseOpts.Increment - if increment <= 0 { - if backendIncrement > 0 { - increment = backendIncrement - } else { - increment = systemView.DefaultLeaseTTL() - } - } - - // We are proposing a time of the current time plus the increment - proposedExpiration := now.Add(increment) - // If the proposed expiration is after the maximum TTL of the lease, // cap the increment to whatever is left - if maxValidTime.Before(proposedExpiration) { - increment = maxValidTime.Sub(now) + if maxValidTTL-ttl < 0 { + warnings = append(warnings, + fmt.Sprintf("TTL of %q exceeded the effective max_ttl of %q; TTL value is capped accordingly", ttl, maxValidTTL)) + ttl = maxValidTTL } - - // Set the lease - leaseOpts.TTL = increment - - return &logical.Response{Auth: req.Auth, Secret: req.Secret}, nil } + + return ttl, warnings, nil } diff --git a/logical/framework/lease_test.go b/logical/framework/lease_test.go index ede8d6bec3..86ef28222e 100644 --- a/logical/framework/lease_test.go +++ b/logical/framework/lease_test.go @@ -1,27 +1,26 @@ package framework import ( - "context" "testing" "time" "github.com/hashicorp/vault/logical" ) -func TestLeaseExtend(t *testing.T) { - +func TestCalculateTTL(t *testing.T) { testSysView := logical.StaticSystemView{ DefaultLeaseTTLVal: 5 * time.Hour, MaxLeaseTTLVal: 30 * time.Hour, } - now := time.Now().Round(time.Hour) - cases := map[string]struct { + Increment time.Duration BackendDefault time.Duration BackendMax time.Duration - Increment time.Duration + Period time.Duration + ExplicitMaxTTL time.Duration Result time.Duration + Warnings int Error bool }{ "valid request, good bounds, increment is preferred": { @@ -52,6 +51,7 @@ func TestLeaseExtend(t *testing.T) { BackendDefault: 40 * time.Hour, BackendMax: 45 * time.Hour, Result: 30 * time.Hour, + Warnings: 1, }, "all request values are larger than the system view, so the system view limits": { @@ -59,6 +59,7 @@ func TestLeaseExtend(t *testing.T) { BackendMax: 50 * time.Hour, Increment: 40 * time.Hour, Result: 30 * time.Hour, + Warnings: 1, }, "request within backend max": { @@ -73,6 +74,7 @@ func TestLeaseExtend(t *testing.T) { BackendMax: 4 * time.Hour, Increment: 5 * time.Hour, Result: 4 * time.Hour, + Warnings: 1, }, "request is negative, no backend default, use sysview": { @@ -83,22 +85,34 @@ func TestLeaseExtend(t *testing.T) { "lease increment too large": { Increment: 40 * time.Hour, Result: 30 * time.Hour, + Warnings: 1, + }, + + "periodic, good request, period is preferred": { + Increment: 3 * time.Hour, + BackendDefault: 4 * time.Hour, + BackendMax: 2 * time.Hour, + Period: 1 * time.Hour, + Result: 1 * time.Hour, + }, + + "period too large, explicit max ttl is preferred": { + Period: 2 * time.Hour, + ExplicitMaxTTL: 1 * time.Hour, + Result: 1 * time.Hour, + Warnings: 1, + }, + + "period too large, capped by backend max": { + Period: 2 * time.Hour, + BackendMax: 1 * time.Hour, + Result: 1 * time.Hour, + Warnings: 1, }, } for name, tc := range cases { - req := &logical.Request{ - Auth: &logical.Auth{ - LeaseOptions: logical.LeaseOptions{ - TTL: 1 * time.Hour, - IssueTime: now, - Increment: tc.Increment, - }, - }, - } - - callback := LeaseExtend(tc.BackendDefault, tc.BackendMax, testSysView) - resp, err := callback(context.Background(), req, nil) + ttl, warnings, err := CalculateTTL(testSysView, tc.Increment, tc.BackendDefault, tc.Period, tc.BackendMax, tc.ExplicitMaxTTL, time.Time{}) if (err != nil) != tc.Error { t.Fatalf("bad: %s\nerr: %s", name, err) } @@ -107,9 +121,14 @@ func TestLeaseExtend(t *testing.T) { } // Round it to the nearest hour - lease := now.Add(resp.Auth.TTL).Round(time.Hour).Sub(now) + now := time.Now().Round(time.Hour) + lease := now.Add(ttl).Round(time.Hour).Sub(now) if lease != tc.Result { t.Fatalf("bad: %s\nlease: %s", name, lease) } + + if tc.Warnings != len(warnings) { + t.Fatalf("bad: %s\nwarning count mismatch, expect %d, got %d: %#v", name, tc.Warnings, len(warnings), warnings) + } } } diff --git a/logical/lease.go b/logical/lease.go index 9661796ca4..90c0894766 100644 --- a/logical/lease.go +++ b/logical/lease.go @@ -7,10 +7,13 @@ import ( // LeaseOptions is an embeddable struct to capture common lease // settings between a Secret and Auth type LeaseOptions struct { - // Lease is the duration that this secret is valid for. Vault + // TTL is the duration that this secret is valid for. Vault // will automatically revoke it after the duration. TTL time.Duration `json:"lease"` + // MaxTTL is the maximum duration that this secret is valid for. + MaxTTL time.Duration `json:"max_ttl"` + // Renewable, if true, means that this secret can be renewed. Renewable bool `json:"renewable"` diff --git a/logical/plugin/pb/backend.pb.go b/logical/plugin/pb/backend.pb.go index e2a2a3116c..aab0cb2185 100644 --- a/logical/plugin/pb/backend.pb.go +++ b/logical/plugin/pb/backend.pb.go @@ -581,6 +581,7 @@ type LeaseOptions struct { Renewable bool `sentinel:"" protobuf:"varint,2,opt,name=renewable" json:"renewable,omitempty"` Increment int64 `sentinel:"" protobuf:"varint,3,opt,name=increment" json:"increment,omitempty"` IssueTime *google_protobuf.Timestamp `sentinel:"" protobuf:"bytes,4,opt,name=issue_time,json=issueTime" json:"issue_time,omitempty"` + MaxTTL int64 `sentinel:"" protobuf:"varint,5,opt,name=MaxTTL" json:"MaxTTL,omitempty"` } func (m *LeaseOptions) Reset() { *m = LeaseOptions{} } @@ -616,6 +617,13 @@ func (m *LeaseOptions) GetIssueTime() *google_protobuf.Timestamp { return nil } +func (m *LeaseOptions) GetMaxTTL() int64 { + if m != nil { + return m.MaxTTL + } + return 0 +} + type Secret struct { LeaseOptions *LeaseOptions `sentinel:"" protobuf:"bytes,1,opt,name=lease_options,json=leaseOptions" json:"lease_options,omitempty"` // InternalData is a JSON object that is stored with the secret. @@ -2353,137 +2361,137 @@ var _SystemView_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("logical/plugin/pb/backend.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 2101 bytes of a gzipped FileDescriptorProto + // 2112 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x5b, 0x6f, 0xdb, 0xc8, 0x15, 0x86, 0x24, 0x4b, 0xa2, 0x8e, 0x24, 0x5f, 0x26, 0x4e, 0xca, 0x28, 0xd9, 0x5a, 0xe5, 0x22, 0x59, 0x6d, 0xd0, 0xc8, 0x89, 0x7a, 0xcb, 0xb6, 0xd8, 0x2d, 0x5c, 0xdb, 0x9b, 0x75, 0xd7, 0xde, 0x35, 0x68, 0xa7, 0xdb, 0xa2, 0x05, 0xb4, 0x63, 0xf2, 0x58, 0x26, 0x4c, 0x91, 0xec, 0x70, 0x68, - 0x47, 0x4f, 0xfd, 0x17, 0xed, 0x5f, 0xe9, 0x5b, 0x5f, 0x0b, 0xf4, 0xb9, 0xbf, 0xa0, 0xef, 0x7d, - 0xe8, 0x2f, 0x28, 0xe6, 0x42, 0x6a, 0x28, 0xc9, 0x4d, 0x0a, 0xb4, 0x6f, 0x73, 0x2e, 0x33, 0xe7, - 0xc2, 0x73, 0xbe, 0x33, 0x43, 0xd8, 0x09, 0xe3, 0x49, 0xe0, 0xd1, 0x70, 0x37, 0x09, 0xb3, 0x49, - 0x10, 0xed, 0x26, 0x17, 0xbb, 0x17, 0xd4, 0xbb, 0xc6, 0xc8, 0x1f, 0x26, 0x2c, 0xe6, 0x31, 0xa9, - 0x26, 0x17, 0xbd, 0x9d, 0x49, 0x1c, 0x4f, 0x42, 0xdc, 0x95, 0x9c, 0x8b, 0xec, 0x72, 0x97, 0x07, - 0x53, 0x4c, 0x39, 0x9d, 0x26, 0x4a, 0xc9, 0x69, 0x42, 0xfd, 0x70, 0x9a, 0xf0, 0x99, 0xd3, 0x87, - 0xc6, 0x17, 0x48, 0x7d, 0x64, 0xe4, 0x01, 0x34, 0xae, 0xe4, 0xca, 0xae, 0xf4, 0x6b, 0x83, 0x96, - 0xab, 0x29, 0xe7, 0xb7, 0x00, 0xa7, 0x62, 0xcf, 0x21, 0x63, 0x31, 0x23, 0x0f, 0xc1, 0x42, 0xc6, - 0xc6, 0x7c, 0x96, 0xa0, 0x5d, 0xe9, 0x57, 0x06, 0x5d, 0xb7, 0x89, 0x8c, 0x9d, 0xcf, 0x12, 0x24, - 0xdf, 0x01, 0xb1, 0x1c, 0x4f, 0xd3, 0x89, 0x5d, 0xed, 0x57, 0xc4, 0x09, 0xc8, 0xd8, 0x49, 0x3a, - 0xc9, 0xf7, 0x78, 0xb1, 0x8f, 0x76, 0xad, 0x5f, 0x19, 0xd4, 0xe4, 0x9e, 0xfd, 0xd8, 0x47, 0xe7, - 0x8f, 0x15, 0xa8, 0x9f, 0x52, 0x7e, 0x95, 0x12, 0x02, 0x6b, 0x2c, 0x8e, 0xb9, 0x36, 0x2e, 0xd7, - 0x64, 0x00, 0x1b, 0x59, 0x44, 0x33, 0x7e, 0x85, 0x11, 0x0f, 0x3c, 0xca, 0xd1, 0xb7, 0xab, 0x52, - 0xbc, 0xc8, 0x26, 0x1f, 0x42, 0x37, 0x8c, 0x3d, 0x1a, 0x8e, 0x53, 0x1e, 0x33, 0x3a, 0x11, 0x76, - 0x84, 0x5e, 0x47, 0x32, 0xcf, 0x14, 0x8f, 0x3c, 0x83, 0xad, 0x14, 0x69, 0x38, 0xbe, 0x65, 0x34, - 0x29, 0x14, 0xd7, 0xd4, 0x81, 0x42, 0xf0, 0x0d, 0xa3, 0x89, 0xd6, 0x75, 0xfe, 0xd2, 0x80, 0xa6, - 0x8b, 0xbf, 0xcf, 0x30, 0xe5, 0x64, 0x1d, 0xaa, 0x81, 0x2f, 0xa3, 0x6d, 0xb9, 0xd5, 0xc0, 0x27, - 0x43, 0x20, 0x2e, 0x26, 0xa1, 0x30, 0x1d, 0xc4, 0xd1, 0x7e, 0x98, 0xa5, 0x1c, 0x99, 0x8e, 0x79, - 0x85, 0x84, 0x3c, 0x86, 0x56, 0x9c, 0x20, 0x93, 0x3c, 0x99, 0x80, 0x96, 0x3b, 0x67, 0x88, 0xc0, - 0x13, 0xca, 0xaf, 0xec, 0x35, 0x29, 0x90, 0x6b, 0xc1, 0xf3, 0x29, 0xa7, 0x76, 0x5d, 0xf1, 0xc4, - 0x9a, 0x38, 0xd0, 0x48, 0xd1, 0x63, 0xc8, 0xed, 0x46, 0xbf, 0x32, 0x68, 0x8f, 0x60, 0x98, 0x5c, - 0x0c, 0xcf, 0x24, 0xc7, 0xd5, 0x12, 0xf2, 0x18, 0xd6, 0x44, 0x5e, 0xec, 0xa6, 0xd4, 0xb0, 0x84, - 0xc6, 0x5e, 0xc6, 0xaf, 0x5c, 0xc9, 0x25, 0x23, 0x68, 0xaa, 0x6f, 0x9a, 0xda, 0x56, 0xbf, 0x36, - 0x68, 0x8f, 0x6c, 0xa1, 0xa0, 0xa3, 0x1c, 0xaa, 0x32, 0x48, 0x0f, 0x23, 0xce, 0x66, 0x6e, 0xae, - 0x48, 0xbe, 0x07, 0x1d, 0x2f, 0x0c, 0x30, 0xe2, 0x63, 0x1e, 0x5f, 0x63, 0x64, 0xb7, 0xa4, 0x47, - 0x6d, 0xc5, 0x3b, 0x17, 0x2c, 0x32, 0x82, 0xfb, 0xa6, 0xca, 0x98, 0x7a, 0x1e, 0xa6, 0x69, 0xcc, - 0x6c, 0x90, 0xba, 0xf7, 0x0c, 0xdd, 0x3d, 0x2d, 0x12, 0xc7, 0xfa, 0x41, 0x9a, 0x84, 0x74, 0x36, - 0x8e, 0xe8, 0x14, 0xed, 0xb6, 0x3a, 0x56, 0xf3, 0xbe, 0xa2, 0x53, 0x24, 0x3b, 0xd0, 0x9e, 0xc6, - 0x59, 0xc4, 0xc7, 0x49, 0x1c, 0x44, 0xdc, 0xee, 0x48, 0x0d, 0x90, 0xac, 0x53, 0xc1, 0x21, 0x1f, - 0x80, 0xa2, 0x54, 0x31, 0x76, 0x55, 0x5e, 0x25, 0x47, 0x96, 0xe3, 0x13, 0x58, 0x57, 0xe2, 0xc2, - 0x9f, 0x75, 0xa9, 0xd2, 0x95, 0xdc, 0xc2, 0x93, 0x17, 0xd0, 0x92, 0xf5, 0x10, 0x44, 0x97, 0xb1, - 0xbd, 0x21, 0xf3, 0x76, 0xcf, 0x48, 0x8b, 0xa8, 0x89, 0xa3, 0xe8, 0x32, 0x76, 0xad, 0x5b, 0xbd, - 0x22, 0x9f, 0xc2, 0xa3, 0x52, 0xbc, 0x0c, 0xa7, 0x34, 0x88, 0x82, 0x68, 0x32, 0xce, 0x52, 0x4c, - 0xed, 0x4d, 0x59, 0xe1, 0xb6, 0x11, 0xb5, 0x9b, 0x2b, 0xbc, 0x49, 0x31, 0x25, 0x8f, 0xa0, 0x25, - 0xea, 0x96, 0xcf, 0xc6, 0x81, 0x6f, 0x6f, 0x49, 0x97, 0x2c, 0xc5, 0x38, 0xf2, 0xc9, 0x47, 0xb0, - 0x91, 0xc4, 0x61, 0xe0, 0xcd, 0xc6, 0xf1, 0x0d, 0x32, 0x16, 0xf8, 0x68, 0x93, 0x7e, 0x65, 0x60, - 0xb9, 0xeb, 0x8a, 0xfd, 0xb5, 0xe6, 0xae, 0x6a, 0x8d, 0x7b, 0x52, 0x71, 0xa9, 0x35, 0x86, 0x00, - 0x5e, 0x1c, 0x45, 0xe8, 0xc9, 0xf2, 0xdb, 0x96, 0x11, 0xae, 0x8b, 0x08, 0xf7, 0x0b, 0xae, 0x6b, - 0x68, 0xf4, 0x3e, 0x87, 0x8e, 0x59, 0x0a, 0x64, 0x13, 0x6a, 0xd7, 0x38, 0xd3, 0xe5, 0x2f, 0x96, - 0xa4, 0x0f, 0xf5, 0x1b, 0x1a, 0x66, 0x28, 0x4b, 0x5e, 0x17, 0xa2, 0xda, 0xe2, 0x2a, 0xc1, 0x4f, - 0xab, 0xaf, 0x2a, 0x0e, 0x85, 0xfa, 0x5e, 0x18, 0xd0, 0x74, 0xe1, 0x3b, 0x55, 0xde, 0xfd, 0x9d, - 0xaa, 0xab, 0xbe, 0x13, 0x81, 0x35, 0x59, 0x29, 0xaa, 0x7f, 0xe4, 0xda, 0xf9, 0x57, 0x0d, 0xd6, - 0x44, 0x7d, 0x93, 0x1f, 0x41, 0x37, 0x44, 0x9a, 0xe2, 0x38, 0x4e, 0x44, 0x0c, 0xa9, 0xb4, 0xd2, - 0x1e, 0x6d, 0x0a, 0xcf, 0x8e, 0x85, 0xe0, 0x6b, 0xc5, 0x77, 0x3b, 0xa1, 0x41, 0x09, 0xd4, 0x08, - 0x22, 0x8e, 0x2c, 0xa2, 0xe1, 0x58, 0xf6, 0x9b, 0xb2, 0xdc, 0xc9, 0x99, 0x07, 0xa2, 0xef, 0x16, - 0x4b, 0xb5, 0xb6, 0x5c, 0xaa, 0x3d, 0xb0, 0xe4, 0xe7, 0x09, 0x30, 0xd5, 0x78, 0x52, 0xd0, 0x64, - 0x04, 0xd6, 0x14, 0x39, 0xd5, 0xed, 0x2c, 0xba, 0xee, 0x41, 0xde, 0x96, 0xc3, 0x13, 0x2d, 0x50, - 0x3d, 0x57, 0xe8, 0x2d, 0x35, 0x5d, 0x63, 0xb9, 0xe9, 0x7a, 0x60, 0x15, 0xf9, 0x6a, 0xaa, 0x22, - 0xca, 0x69, 0x81, 0xe4, 0x09, 0xb2, 0x20, 0xf6, 0x6d, 0x4b, 0xd6, 0xa2, 0xa6, 0x04, 0x0e, 0x47, - 0xd9, 0x54, 0x55, 0x69, 0x4b, 0xe1, 0x70, 0x94, 0x4d, 0x97, 0x8b, 0x12, 0x16, 0x8a, 0x72, 0x07, - 0xea, 0x54, 0x7c, 0x49, 0xd9, 0xa5, 0xed, 0x51, 0x4b, 0xfa, 0x2f, 0x18, 0xae, 0xe2, 0x93, 0x21, - 0x74, 0x27, 0x2c, 0xce, 0x92, 0xb1, 0x24, 0x31, 0xb5, 0x3b, 0x32, 0x50, 0x43, 0xb1, 0x23, 0xe5, - 0x7b, 0x4a, 0xdc, 0xfb, 0x19, 0x74, 0x4b, 0xa1, 0xaf, 0xa8, 0xb1, 0x6d, 0xb3, 0xc6, 0x5a, 0x66, - 0x5d, 0xfd, 0xa9, 0x02, 0x1d, 0xf3, 0x9b, 0x8a, 0xcd, 0xe7, 0xe7, 0xc7, 0x72, 0x73, 0xcd, 0x15, - 0x4b, 0x01, 0xb8, 0x0c, 0x23, 0xbc, 0xa5, 0x17, 0xa1, 0x3a, 0xc0, 0x72, 0xe7, 0x0c, 0x21, 0x0d, - 0x22, 0x8f, 0xe1, 0x14, 0x23, 0xae, 0xe7, 0xd1, 0x9c, 0x41, 0x3e, 0x01, 0x08, 0xd2, 0x34, 0xc3, - 0xb1, 0x18, 0x99, 0x12, 0x94, 0xdb, 0xa3, 0xde, 0x50, 0xcd, 0xd3, 0x61, 0x3e, 0x4f, 0x87, 0xe7, - 0xf9, 0x3c, 0x75, 0x5b, 0x52, 0x5b, 0xd0, 0xce, 0x1f, 0xa0, 0xa1, 0xf0, 0xf8, 0xff, 0x5a, 0x8f, - 0x0f, 0xc1, 0x52, 0x67, 0x07, 0xbe, 0xae, 0xc5, 0xa6, 0xa4, 0x8f, 0x7c, 0xe7, 0x6f, 0x15, 0xb0, - 0x5c, 0x4c, 0x93, 0x38, 0x4a, 0xd1, 0x98, 0x17, 0x95, 0x77, 0xce, 0x8b, 0xea, 0xca, 0x79, 0x91, - 0x4f, 0xa1, 0x9a, 0x31, 0x85, 0x7a, 0x60, 0x31, 0xf4, 0x03, 0x86, 0x1e, 0xd7, 0x13, 0xab, 0xa0, - 0x85, 0xec, 0x96, 0x32, 0x01, 0x74, 0xa9, 0x2c, 0xf5, 0x96, 0x5b, 0xd0, 0xe4, 0xa5, 0x09, 0xb3, - 0x6a, 0x80, 0x6d, 0x2b, 0x98, 0x55, 0xee, 0x2e, 0xe3, 0xac, 0xf3, 0xd7, 0x2a, 0x6c, 0x2e, 0x8a, - 0x57, 0x7c, 0xec, 0x6d, 0xa8, 0xab, 0x2e, 0xd1, 0x95, 0xc2, 0x97, 0xfa, 0xa3, 0xb6, 0xd0, 0x1f, - 0x3f, 0x87, 0xae, 0xc7, 0x50, 0x4e, 0xdf, 0xf7, 0xfd, 0xca, 0x9d, 0x7c, 0x83, 0x60, 0x91, 0x8f, - 0x61, 0x53, 0x78, 0x99, 0xa0, 0x3f, 0x07, 0x2d, 0x35, 0xaa, 0x37, 0x34, 0xbf, 0x80, 0xad, 0x67, - 0xb0, 0x95, 0xab, 0xce, 0x1b, 0xac, 0x51, 0xd2, 0x3d, 0xcc, 0xfb, 0xec, 0x01, 0x34, 0x2e, 0x63, - 0x36, 0xa5, 0x5c, 0x77, 0xb4, 0xa6, 0x44, 0x59, 0x14, 0xfe, 0xca, 0xab, 0x82, 0xa5, 0xca, 0x22, - 0x67, 0x8a, 0x0b, 0x94, 0xe8, 0xe0, 0xe2, 0x72, 0x23, 0xbb, 0xdb, 0x72, 0xad, 0xfc, 0x52, 0xe3, - 0xfc, 0x1a, 0x36, 0x16, 0xe6, 0xd9, 0x8a, 0x44, 0xce, 0xcd, 0x57, 0x4b, 0xe6, 0x4b, 0x27, 0xd7, - 0x16, 0x4e, 0xfe, 0x0d, 0x6c, 0x7d, 0x41, 0x23, 0x3f, 0x44, 0x7d, 0xfe, 0x1e, 0x9b, 0x48, 0xc4, - 0xd7, 0xd7, 0xab, 0xb1, 0xbe, 0x38, 0x75, 0xdd, 0x96, 0xe6, 0x1c, 0xf9, 0xe4, 0x09, 0x34, 0x99, - 0xd2, 0xd6, 0x85, 0xd7, 0x36, 0x06, 0xae, 0x9b, 0xcb, 0x9c, 0x6f, 0x81, 0x94, 0x8e, 0x16, 0x37, - 0xab, 0x19, 0x19, 0x88, 0x02, 0x54, 0x45, 0xa1, 0x0b, 0xbb, 0x63, 0xd6, 0x91, 0x5b, 0x48, 0x49, - 0x1f, 0x6a, 0xc8, 0x98, 0x36, 0x21, 0x27, 0xde, 0xfc, 0x1e, 0xeb, 0x0a, 0x91, 0xf3, 0x43, 0xd8, - 0x3a, 0x4b, 0xd0, 0x0b, 0x68, 0x28, 0xef, 0xa0, 0xca, 0xc0, 0x0e, 0xd4, 0x45, 0x92, 0xf3, 0x9e, - 0x95, 0x20, 0xa6, 0xc4, 0x8a, 0xef, 0x7c, 0x0b, 0xb6, 0xf2, 0xeb, 0xf0, 0x6d, 0x90, 0x72, 0x8c, - 0x3c, 0xdc, 0xbf, 0x42, 0xef, 0xfa, 0x7f, 0x18, 0xf9, 0x0d, 0x3c, 0x5c, 0x65, 0x21, 0xf7, 0xaf, - 0xed, 0x09, 0x6a, 0x7c, 0x19, 0x67, 0x91, 0xb2, 0x61, 0xb9, 0x20, 0x59, 0x9f, 0x0b, 0x8e, 0xf8, - 0x8e, 0x28, 0xf6, 0xa5, 0x1a, 0xfa, 0x34, 0x95, 0xe7, 0xa3, 0x76, 0x77, 0x3e, 0xfe, 0x5c, 0x81, - 0xd6, 0x19, 0xf2, 0x2c, 0x91, 0xb1, 0x3c, 0x82, 0xd6, 0x05, 0x8b, 0xaf, 0x91, 0xcd, 0x43, 0xb1, - 0x14, 0xe3, 0xc8, 0x27, 0x2f, 0xa1, 0xb1, 0x1f, 0x47, 0x97, 0xc1, 0x44, 0xde, 0xc8, 0xdb, 0xa3, - 0x87, 0x0a, 0x5d, 0xf4, 0xde, 0xa1, 0x92, 0xa9, 0xb9, 0xa6, 0x15, 0x49, 0x1f, 0xda, 0xfa, 0xa5, - 0xf2, 0xe6, 0xcd, 0xd1, 0x41, 0x3e, 0x47, 0x0d, 0x56, 0xef, 0x13, 0x68, 0x1b, 0x1b, 0xff, 0xab, - 0xa9, 0xf0, 0x5d, 0x00, 0x69, 0x5d, 0xe5, 0x68, 0x53, 0x85, 0xaa, 0x77, 0x8a, 0xd0, 0x76, 0xa0, - 0x25, 0x6e, 0x1b, 0x4a, 0x4c, 0x60, 0xcd, 0x78, 0xc0, 0xc8, 0xb5, 0xf3, 0x04, 0xb6, 0x8e, 0xa2, - 0x1b, 0x1a, 0x06, 0x3e, 0xe5, 0xf8, 0x25, 0xce, 0x64, 0x0a, 0x96, 0x3c, 0x70, 0xce, 0xa0, 0xa3, - 0x9f, 0x08, 0xef, 0xe5, 0x63, 0x47, 0xfb, 0xf8, 0x9f, 0x9b, 0xe8, 0x63, 0xd8, 0xd0, 0x87, 0x1e, - 0x07, 0xba, 0x85, 0xc4, 0x0c, 0x67, 0x78, 0x19, 0xbc, 0xd5, 0x47, 0x6b, 0xca, 0x79, 0x05, 0x9b, - 0x86, 0x6a, 0x11, 0xce, 0x35, 0xce, 0xd2, 0xfc, 0xe9, 0x24, 0xd6, 0x79, 0x06, 0xaa, 0xf3, 0x0c, - 0x38, 0xb0, 0xae, 0x77, 0xbe, 0x46, 0x7e, 0x47, 0x74, 0x5f, 0x16, 0x8e, 0xbc, 0x46, 0x7d, 0xf8, - 0x53, 0xa8, 0xa3, 0x88, 0xd4, 0x1c, 0x61, 0x66, 0x06, 0x5c, 0x25, 0x5e, 0x61, 0xf0, 0x55, 0x61, - 0xf0, 0x34, 0x53, 0x06, 0xdf, 0xf3, 0x2c, 0xe7, 0xc3, 0xc2, 0x8d, 0xd3, 0x8c, 0xdf, 0xf5, 0x45, - 0x9f, 0xc0, 0x96, 0x56, 0x3a, 0xc0, 0x10, 0x39, 0xde, 0x11, 0xd2, 0x53, 0x20, 0x25, 0xb5, 0xbb, - 0x8e, 0x7b, 0x0c, 0xd6, 0xf9, 0xf9, 0x71, 0x21, 0x2d, 0x63, 0xa3, 0xf3, 0x29, 0x6c, 0x9d, 0x65, - 0x7e, 0x7c, 0xca, 0x82, 0x9b, 0x20, 0xc4, 0x89, 0x32, 0x96, 0xbf, 0xdc, 0x2a, 0xc6, 0xcb, 0x6d, - 0xe5, 0x34, 0x72, 0x06, 0x40, 0x4a, 0xdb, 0x8b, 0xef, 0x96, 0x66, 0x7e, 0xac, 0x5b, 0x58, 0xae, - 0x9d, 0x01, 0x74, 0xce, 0xa9, 0x98, 0xf7, 0xbe, 0xd2, 0xb1, 0xa1, 0xc9, 0x15, 0xad, 0xd5, 0x72, - 0xd2, 0x19, 0xc1, 0xf6, 0x3e, 0xf5, 0xae, 0x82, 0x68, 0x72, 0x10, 0xa4, 0xe2, 0x62, 0xa3, 0x77, - 0xf4, 0xc0, 0xf2, 0x35, 0x43, 0x6f, 0x29, 0x68, 0xe7, 0x39, 0xdc, 0x37, 0xde, 0xa7, 0x67, 0x9c, - 0xe6, 0xf9, 0xd8, 0x86, 0x7a, 0x2a, 0x28, 0xb9, 0xa3, 0xee, 0x2a, 0xc2, 0xf9, 0x0a, 0xb6, 0xcd, - 0x01, 0x2c, 0xae, 0x1f, 0x79, 0xe0, 0xf2, 0x62, 0x50, 0x31, 0x2e, 0x06, 0x3a, 0x67, 0xd5, 0xf9, - 0x3c, 0xd9, 0x84, 0xda, 0x2f, 0xbf, 0x39, 0xd7, 0xc5, 0x2e, 0x96, 0xce, 0xef, 0x84, 0xf9, 0xf2, - 0x79, 0xca, 0x7c, 0xe9, 0x76, 0x50, 0x79, 0x9f, 0xdb, 0xc1, 0x8a, 0x7a, 0x7b, 0x0e, 0x5b, 0x27, - 0x61, 0xec, 0x5d, 0x1f, 0x46, 0x46, 0x36, 0x6c, 0x68, 0x62, 0x64, 0x26, 0x23, 0x27, 0x9d, 0x8f, - 0x60, 0xe3, 0x38, 0xf6, 0x68, 0x78, 0x22, 0x9e, 0x19, 0x45, 0x16, 0xe4, 0x0f, 0x03, 0xad, 0xaa, - 0x08, 0xe7, 0x39, 0xc0, 0xfc, 0xa9, 0x24, 0xe0, 0x97, 0xe1, 0x34, 0xe6, 0x38, 0xa6, 0xbe, 0x9f, - 0x57, 0x10, 0x28, 0xd6, 0x9e, 0xef, 0xb3, 0xd1, 0x3f, 0xab, 0xd0, 0xfc, 0x85, 0x02, 0x35, 0xf2, - 0x19, 0x74, 0x4b, 0x23, 0x8c, 0xdc, 0x97, 0x6f, 0xa5, 0xc5, 0x81, 0xd9, 0x7b, 0xb0, 0xc4, 0x56, - 0x0e, 0xbd, 0x80, 0x8e, 0x39, 0xa0, 0x88, 0x1c, 0x46, 0xf2, 0xc7, 0x4d, 0x4f, 0x9e, 0xb4, 0x3c, - 0xbd, 0xce, 0x60, 0x7b, 0xd5, 0xe8, 0x20, 0x8f, 0xe7, 0x16, 0x96, 0xc7, 0x56, 0xef, 0x83, 0xbb, - 0xa4, 0xf9, 0xc8, 0x69, 0xee, 0x87, 0x48, 0xa3, 0x2c, 0x31, 0x3d, 0x98, 0x2f, 0xc9, 0x4b, 0xe8, - 0x96, 0xc0, 0x53, 0xc5, 0xb9, 0x84, 0xa7, 0xe6, 0x96, 0xa7, 0x50, 0x97, 0x80, 0x4d, 0xba, 0xa5, - 0xc9, 0xd1, 0x5b, 0x2f, 0x48, 0x65, 0xbb, 0x0f, 0x6b, 0xf2, 0x99, 0x68, 0x18, 0x96, 0x3b, 0x0a, - 0x34, 0x1f, 0xfd, 0xbd, 0x02, 0xcd, 0xfc, 0x17, 0xcf, 0x4b, 0x58, 0x13, 0xb8, 0x48, 0xee, 0x19, - 0xd0, 0x92, 0x63, 0x6a, 0x6f, 0x7b, 0x81, 0xa9, 0x0c, 0x0c, 0xa1, 0xf6, 0x1a, 0x39, 0x21, 0x86, - 0x50, 0x03, 0x64, 0xef, 0x5e, 0x99, 0x57, 0xe8, 0x9f, 0x66, 0x65, 0x7d, 0x8d, 0x6f, 0x25, 0xfd, - 0x02, 0xb9, 0x7e, 0x02, 0x0d, 0x85, 0x3c, 0x2a, 0x29, 0x4b, 0x98, 0xa5, 0x3e, 0xfe, 0x32, 0x46, - 0x8d, 0xfe, 0x51, 0x03, 0x38, 0x9b, 0xa5, 0x1c, 0xa7, 0xbf, 0x0a, 0xf0, 0x96, 0x3c, 0x83, 0x8d, - 0x03, 0xbc, 0xa4, 0x59, 0xc8, 0xe5, 0x0b, 0x42, 0x74, 0x98, 0x91, 0x13, 0x79, 0x09, 0x2a, 0x00, - 0xec, 0x29, 0xb4, 0x4f, 0xe8, 0xdb, 0x77, 0xeb, 0x7d, 0x06, 0xdd, 0x12, 0x2e, 0x69, 0x17, 0x17, - 0x91, 0x4e, 0xbb, 0xb8, 0x8c, 0x60, 0x4f, 0xa1, 0xa9, 0xd1, 0xca, 0xb4, 0x21, 0x71, 0xbd, 0x84, - 0x62, 0x3f, 0x86, 0x8d, 0x05, 0xac, 0x32, 0xf5, 0xe5, 0x6f, 0xa8, 0x95, 0x58, 0xf6, 0x4a, 0xbc, - 0x00, 0xca, 0x78, 0x65, 0x6e, 0x7c, 0xa8, 0x30, 0x62, 0x15, 0xa0, 0xbd, 0x2e, 0xbf, 0x1d, 0xe4, - 0xcb, 0xc9, 0x5e, 0x84, 0x94, 0x1c, 0xd0, 0xf2, 0x83, 0x56, 0x41, 0xd3, 0x0b, 0xe8, 0x98, 0xa8, - 0xb2, 0xd4, 0x82, 0xcb, 0x90, 0xf3, 0x7d, 0x80, 0x39, 0xb0, 0x98, 0xfa, 0xb2, 0x3c, 0x16, 0x30, - 0xe7, 0xa2, 0x21, 0x5f, 0x1b, 0x3f, 0xf8, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4e, 0x53, 0x71, - 0xaf, 0xd8, 0x15, 0x00, 0x00, + 0x47, 0x4f, 0xfd, 0x17, 0xfd, 0x1b, 0x7d, 0xed, 0x5b, 0x5f, 0x0b, 0xf4, 0xb9, 0xbf, 0xa0, 0xef, + 0x7d, 0xe8, 0x2f, 0x28, 0xe6, 0x42, 0x6a, 0x28, 0xc9, 0x4d, 0x0a, 0xb4, 0x6f, 0x73, 0x2e, 0x33, + 0xe7, 0xc2, 0x73, 0xbe, 0x33, 0x43, 0xd8, 0x09, 0xe3, 0x49, 0xe0, 0xd1, 0x70, 0x37, 0x09, 0xb3, + 0x49, 0x10, 0xed, 0x26, 0x17, 0xbb, 0x17, 0xd4, 0xbb, 0xc6, 0xc8, 0x1f, 0x26, 0x2c, 0xe6, 0x31, + 0xa9, 0x26, 0x17, 0xbd, 0x9d, 0x49, 0x1c, 0x4f, 0x42, 0xdc, 0x95, 0x9c, 0x8b, 0xec, 0x72, 0x97, + 0x07, 0x53, 0x4c, 0x39, 0x9d, 0x26, 0x4a, 0xc9, 0x69, 0x42, 0xfd, 0x70, 0x9a, 0xf0, 0x99, 0xd3, + 0x87, 0xc6, 0x17, 0x48, 0x7d, 0x64, 0xe4, 0x01, 0x34, 0xae, 0xe4, 0xca, 0xae, 0xf4, 0x6b, 0x83, + 0x96, 0xab, 0x29, 0xe7, 0xb7, 0x00, 0xa7, 0x62, 0xcf, 0x21, 0x63, 0x31, 0x23, 0x0f, 0xc1, 0x42, + 0xc6, 0xc6, 0x7c, 0x96, 0xa0, 0x5d, 0xe9, 0x57, 0x06, 0x5d, 0xb7, 0x89, 0x8c, 0x9d, 0xcf, 0x12, + 0x24, 0xdf, 0x01, 0xb1, 0x1c, 0x4f, 0xd3, 0x89, 0x5d, 0xed, 0x57, 0xc4, 0x09, 0xc8, 0xd8, 0x49, + 0x3a, 0xc9, 0xf7, 0x78, 0xb1, 0x8f, 0x76, 0xad, 0x5f, 0x19, 0xd4, 0xe4, 0x9e, 0xfd, 0xd8, 0x47, + 0xe7, 0x8f, 0x15, 0xa8, 0x9f, 0x52, 0x7e, 0x95, 0x12, 0x02, 0x6b, 0x2c, 0x8e, 0xb9, 0x36, 0x2e, + 0xd7, 0x64, 0x00, 0x1b, 0x59, 0x44, 0x33, 0x7e, 0x85, 0x11, 0x0f, 0x3c, 0xca, 0xd1, 0xb7, 0xab, + 0x52, 0xbc, 0xc8, 0x26, 0x1f, 0x42, 0x37, 0x8c, 0x3d, 0x1a, 0x8e, 0x53, 0x1e, 0x33, 0x3a, 0x11, + 0x76, 0x84, 0x5e, 0x47, 0x32, 0xcf, 0x14, 0x8f, 0x3c, 0x83, 0xad, 0x14, 0x69, 0x38, 0xbe, 0x65, + 0x34, 0x29, 0x14, 0xd7, 0xd4, 0x81, 0x42, 0xf0, 0x0d, 0xa3, 0x89, 0xd6, 0x75, 0xfe, 0xd2, 0x80, + 0xa6, 0x8b, 0xbf, 0xcf, 0x30, 0xe5, 0x64, 0x1d, 0xaa, 0x81, 0x2f, 0xa3, 0x6d, 0xb9, 0xd5, 0xc0, + 0x27, 0x43, 0x20, 0x2e, 0x26, 0xa1, 0x30, 0x1d, 0xc4, 0xd1, 0x7e, 0x98, 0xa5, 0x1c, 0x99, 0x8e, + 0x79, 0x85, 0x84, 0x3c, 0x86, 0x56, 0x9c, 0x20, 0x93, 0x3c, 0x99, 0x80, 0x96, 0x3b, 0x67, 0x88, + 0xc0, 0x13, 0xca, 0xaf, 0xec, 0x35, 0x29, 0x90, 0x6b, 0xc1, 0xf3, 0x29, 0xa7, 0x76, 0x5d, 0xf1, + 0xc4, 0x9a, 0x38, 0xd0, 0x48, 0xd1, 0x63, 0xc8, 0xed, 0x46, 0xbf, 0x32, 0x68, 0x8f, 0x60, 0x98, + 0x5c, 0x0c, 0xcf, 0x24, 0xc7, 0xd5, 0x12, 0xf2, 0x18, 0xd6, 0x44, 0x5e, 0xec, 0xa6, 0xd4, 0xb0, + 0x84, 0xc6, 0x5e, 0xc6, 0xaf, 0x5c, 0xc9, 0x25, 0x23, 0x68, 0xaa, 0x6f, 0x9a, 0xda, 0x56, 0xbf, + 0x36, 0x68, 0x8f, 0x6c, 0xa1, 0xa0, 0xa3, 0x1c, 0xaa, 0x32, 0x48, 0x0f, 0x23, 0xce, 0x66, 0x6e, + 0xae, 0x48, 0xbe, 0x07, 0x1d, 0x2f, 0x0c, 0x30, 0xe2, 0x63, 0x1e, 0x5f, 0x63, 0x64, 0xb7, 0xa4, + 0x47, 0x6d, 0xc5, 0x3b, 0x17, 0x2c, 0x32, 0x82, 0xfb, 0xa6, 0xca, 0x98, 0x7a, 0x1e, 0xa6, 0x69, + 0xcc, 0x6c, 0x90, 0xba, 0xf7, 0x0c, 0xdd, 0x3d, 0x2d, 0x12, 0xc7, 0xfa, 0x41, 0x9a, 0x84, 0x74, + 0x36, 0x8e, 0xe8, 0x14, 0xed, 0xb6, 0x3a, 0x56, 0xf3, 0xbe, 0xa2, 0x53, 0x24, 0x3b, 0xd0, 0x9e, + 0xc6, 0x59, 0xc4, 0xc7, 0x49, 0x1c, 0x44, 0xdc, 0xee, 0x48, 0x0d, 0x90, 0xac, 0x53, 0xc1, 0x21, + 0x1f, 0x80, 0xa2, 0x54, 0x31, 0x76, 0x55, 0x5e, 0x25, 0x47, 0x96, 0xe3, 0x13, 0x58, 0x57, 0xe2, + 0xc2, 0x9f, 0x75, 0xa9, 0xd2, 0x95, 0xdc, 0xc2, 0x93, 0x17, 0xd0, 0x92, 0xf5, 0x10, 0x44, 0x97, + 0xb1, 0xbd, 0x21, 0xf3, 0x76, 0xcf, 0x48, 0x8b, 0xa8, 0x89, 0xa3, 0xe8, 0x32, 0x76, 0xad, 0x5b, + 0xbd, 0x22, 0x9f, 0xc2, 0xa3, 0x52, 0xbc, 0x0c, 0xa7, 0x34, 0x88, 0x82, 0x68, 0x32, 0xce, 0x52, + 0x4c, 0xed, 0x4d, 0x59, 0xe1, 0xb6, 0x11, 0xb5, 0x9b, 0x2b, 0xbc, 0x49, 0x31, 0x25, 0x8f, 0xa0, + 0x25, 0xea, 0x96, 0xcf, 0xc6, 0x81, 0x6f, 0x6f, 0x49, 0x97, 0x2c, 0xc5, 0x38, 0xf2, 0xc9, 0x47, + 0xb0, 0x91, 0xc4, 0x61, 0xe0, 0xcd, 0xc6, 0xf1, 0x0d, 0x32, 0x16, 0xf8, 0x68, 0x93, 0x7e, 0x65, + 0x60, 0xb9, 0xeb, 0x8a, 0xfd, 0xb5, 0xe6, 0xae, 0x6a, 0x8d, 0x7b, 0x52, 0x71, 0xa9, 0x35, 0x86, + 0x00, 0x5e, 0x1c, 0x45, 0xe8, 0xc9, 0xf2, 0xdb, 0x96, 0x11, 0xae, 0x8b, 0x08, 0xf7, 0x0b, 0xae, + 0x6b, 0x68, 0xf4, 0x3e, 0x87, 0x8e, 0x59, 0x0a, 0x64, 0x13, 0x6a, 0xd7, 0x38, 0xd3, 0xe5, 0x2f, + 0x96, 0xa4, 0x0f, 0xf5, 0x1b, 0x1a, 0x66, 0x28, 0x4b, 0x5e, 0x17, 0xa2, 0xda, 0xe2, 0x2a, 0xc1, + 0x4f, 0xab, 0xaf, 0x2a, 0x0e, 0x85, 0xfa, 0x5e, 0x18, 0xd0, 0x74, 0xe1, 0x3b, 0x55, 0xde, 0xfd, + 0x9d, 0xaa, 0xab, 0xbe, 0x13, 0x81, 0x35, 0x59, 0x29, 0xaa, 0x7f, 0xe4, 0xda, 0xf9, 0x57, 0x0d, + 0xd6, 0x44, 0x7d, 0x93, 0x1f, 0x41, 0x37, 0x44, 0x9a, 0xe2, 0x38, 0x4e, 0x44, 0x0c, 0xa9, 0xb4, + 0xd2, 0x1e, 0x6d, 0x0a, 0xcf, 0x8e, 0x85, 0xe0, 0x6b, 0xc5, 0x77, 0x3b, 0xa1, 0x41, 0x09, 0xd4, + 0x08, 0x22, 0x8e, 0x2c, 0xa2, 0xe1, 0x58, 0xf6, 0x9b, 0xb2, 0xdc, 0xc9, 0x99, 0x07, 0xa2, 0xef, + 0x16, 0x4b, 0xb5, 0xb6, 0x5c, 0xaa, 0x3d, 0xb0, 0xe4, 0xe7, 0x09, 0x30, 0xd5, 0x78, 0x52, 0xd0, + 0x64, 0x04, 0xd6, 0x14, 0x39, 0xd5, 0xed, 0x2c, 0xba, 0xee, 0x41, 0xde, 0x96, 0xc3, 0x13, 0x2d, + 0x50, 0x3d, 0x57, 0xe8, 0x2d, 0x35, 0x5d, 0x63, 0xb9, 0xe9, 0x7a, 0x60, 0x15, 0xf9, 0x6a, 0xaa, + 0x22, 0xca, 0x69, 0x81, 0xe4, 0x09, 0xb2, 0x20, 0xf6, 0x6d, 0x4b, 0xd6, 0xa2, 0xa6, 0x04, 0x0e, + 0x47, 0xd9, 0x54, 0x55, 0x69, 0x4b, 0xe1, 0x70, 0x94, 0x4d, 0x97, 0x8b, 0x12, 0x16, 0x8a, 0x72, + 0x07, 0xea, 0x54, 0x7c, 0x49, 0xd9, 0xa5, 0xed, 0x51, 0x4b, 0xfa, 0x2f, 0x18, 0xae, 0xe2, 0x93, + 0x21, 0x74, 0x27, 0x2c, 0xce, 0x92, 0xb1, 0x24, 0x31, 0xb5, 0x3b, 0x32, 0x50, 0x43, 0xb1, 0x23, + 0xe5, 0x7b, 0x4a, 0xdc, 0xfb, 0x19, 0x74, 0x4b, 0xa1, 0xaf, 0xa8, 0xb1, 0x6d, 0xb3, 0xc6, 0x5a, + 0x66, 0x5d, 0xfd, 0xa9, 0x02, 0x1d, 0xf3, 0x9b, 0x8a, 0xcd, 0xe7, 0xe7, 0xc7, 0x72, 0x73, 0xcd, + 0x15, 0x4b, 0x01, 0xb8, 0x0c, 0x23, 0xbc, 0xa5, 0x17, 0xa1, 0x3a, 0xc0, 0x72, 0xe7, 0x0c, 0x21, + 0x0d, 0x22, 0x8f, 0xe1, 0x14, 0x23, 0xae, 0xe7, 0xd1, 0x9c, 0x41, 0x3e, 0x01, 0x08, 0xd2, 0x34, + 0xc3, 0xb1, 0x18, 0x99, 0x12, 0x94, 0xdb, 0xa3, 0xde, 0x50, 0xcd, 0xd3, 0x61, 0x3e, 0x4f, 0x87, + 0xe7, 0xf9, 0x3c, 0x75, 0x5b, 0x52, 0x5b, 0xd0, 0x22, 0xef, 0x27, 0xf4, 0xad, 0xf0, 0xa5, 0xae, + 0xf2, 0xae, 0x28, 0xe7, 0x0f, 0xd0, 0x50, 0x38, 0xfd, 0x7f, 0xad, 0xd3, 0x87, 0x60, 0xa9, 0xb3, + 0x03, 0x5f, 0xd7, 0x68, 0x53, 0xd2, 0x47, 0xbe, 0xf3, 0xb7, 0x0a, 0x58, 0x2e, 0xa6, 0x49, 0x1c, + 0xa5, 0x68, 0xcc, 0x91, 0xca, 0x3b, 0xe7, 0x48, 0x75, 0xe5, 0x1c, 0xc9, 0xa7, 0x53, 0xcd, 0x98, + 0x4e, 0x3d, 0xb0, 0x18, 0xfa, 0x01, 0x43, 0x8f, 0xeb, 0x49, 0x56, 0xd0, 0x42, 0x76, 0x4b, 0x99, + 0x00, 0xc0, 0x54, 0xb6, 0x40, 0xcb, 0x2d, 0x68, 0xf2, 0xd2, 0x84, 0x5f, 0x35, 0xd8, 0xb6, 0x15, + 0xfc, 0x2a, 0x77, 0x97, 0xf1, 0xd7, 0xf9, 0x6b, 0x15, 0x36, 0x17, 0xc5, 0x2b, 0x8a, 0x60, 0x1b, + 0xea, 0xaa, 0x7b, 0x74, 0x05, 0xf1, 0xa5, 0xbe, 0xa9, 0x2d, 0xf4, 0xcd, 0xcf, 0xa1, 0xeb, 0x31, + 0x94, 0x53, 0xf9, 0x7d, 0xbf, 0x7e, 0x27, 0xdf, 0x20, 0x0b, 0xe0, 0x63, 0xd8, 0x14, 0x5e, 0x26, + 0xe8, 0xcf, 0xc1, 0x4c, 0x8d, 0xf0, 0x0d, 0xcd, 0x2f, 0xe0, 0xec, 0x19, 0x6c, 0xe5, 0xaa, 0xf3, + 0xc6, 0x6b, 0x94, 0x74, 0x0f, 0xf3, 0xfe, 0x7b, 0x00, 0x8d, 0xcb, 0x98, 0x4d, 0x29, 0xd7, 0x9d, + 0xae, 0x29, 0x51, 0x16, 0x85, 0xbf, 0xf2, 0x0a, 0x61, 0xa9, 0xb2, 0xc8, 0x99, 0xe2, 0x62, 0x25, + 0x3a, 0xbb, 0xb8, 0xf4, 0xc8, 0xae, 0xb7, 0x5c, 0x2b, 0xbf, 0xec, 0x38, 0xbf, 0x86, 0x8d, 0x85, + 0x39, 0xb7, 0x22, 0x91, 0x73, 0xf3, 0xd5, 0x92, 0xf9, 0xd2, 0xc9, 0xb5, 0x85, 0x93, 0x7f, 0x03, + 0x5b, 0x5f, 0xd0, 0xc8, 0x0f, 0x51, 0x9f, 0xbf, 0xc7, 0x26, 0x72, 0x12, 0xe8, 0x6b, 0xd7, 0x58, + 0x5f, 0xa8, 0xba, 0x6e, 0x4b, 0x73, 0x8e, 0x7c, 0xf2, 0x04, 0x9a, 0x4c, 0x69, 0xeb, 0xc2, 0x6b, + 0x1b, 0x83, 0xd8, 0xcd, 0x65, 0xce, 0xb7, 0x40, 0x4a, 0x47, 0x8b, 0x1b, 0xd7, 0x8c, 0x0c, 0x44, + 0x01, 0xaa, 0xa2, 0xd0, 0x85, 0xdd, 0x31, 0xeb, 0xc8, 0x2d, 0xa4, 0xa4, 0x0f, 0x35, 0x64, 0x4c, + 0x9b, 0x90, 0x93, 0x70, 0x7e, 0xbf, 0x75, 0x85, 0xc8, 0xf9, 0x21, 0x6c, 0x9d, 0x25, 0xe8, 0x05, + 0x34, 0x94, 0x77, 0x53, 0x65, 0x60, 0x07, 0xea, 0x22, 0xc9, 0x79, 0xcf, 0x4a, 0x70, 0x53, 0x62, + 0xc5, 0x77, 0xbe, 0x05, 0x5b, 0xf9, 0x75, 0xf8, 0x36, 0x48, 0x39, 0x46, 0x1e, 0xee, 0x5f, 0xa1, + 0x77, 0xfd, 0x3f, 0x8c, 0xfc, 0x06, 0x1e, 0xae, 0xb2, 0x90, 0xfb, 0xd7, 0xf6, 0x04, 0x35, 0xbe, + 0x8c, 0xb3, 0x48, 0xd9, 0xb0, 0x5c, 0x90, 0xac, 0xcf, 0x05, 0x47, 0x7c, 0x47, 0x14, 0xfb, 0x52, + 0x0d, 0x89, 0x9a, 0xca, 0xf3, 0x51, 0xbb, 0x3b, 0x1f, 0x7f, 0xae, 0x40, 0xeb, 0x0c, 0x79, 0x96, + 0xc8, 0x58, 0x1e, 0x41, 0xeb, 0x82, 0xc5, 0xd7, 0xc8, 0xe6, 0xa1, 0x58, 0x8a, 0x71, 0xe4, 0x93, + 0x97, 0xd0, 0xd8, 0x8f, 0xa3, 0xcb, 0x60, 0x22, 0x6f, 0xea, 0xed, 0xd1, 0x43, 0x85, 0x2e, 0x7a, + 0xef, 0x50, 0xc9, 0xd4, 0xbc, 0xd3, 0x8a, 0xa4, 0x0f, 0x6d, 0xfd, 0x82, 0x79, 0xf3, 0xe6, 0xe8, + 0x20, 0x9f, 0xaf, 0x06, 0xab, 0xf7, 0x09, 0xb4, 0x8d, 0x8d, 0xff, 0xd5, 0xb4, 0xf8, 0x2e, 0x80, + 0xb4, 0xae, 0x72, 0xb4, 0xa9, 0x42, 0xd5, 0x3b, 0x45, 0x68, 0x3b, 0xd0, 0x12, 0xb7, 0x10, 0x25, + 0x26, 0xb0, 0x66, 0x3c, 0x6c, 0xe4, 0xda, 0x79, 0x02, 0x5b, 0x47, 0xd1, 0x0d, 0x0d, 0x03, 0x9f, + 0x72, 0xfc, 0x12, 0x67, 0x32, 0x05, 0x4b, 0x1e, 0x38, 0x67, 0xd0, 0xd1, 0x4f, 0x87, 0xf7, 0xf2, + 0xb1, 0xa3, 0x7d, 0xfc, 0xcf, 0x4d, 0xf4, 0x31, 0x6c, 0xe8, 0x43, 0x8f, 0x03, 0xdd, 0x42, 0x62, + 0xb6, 0x33, 0xbc, 0x0c, 0xde, 0xea, 0xa3, 0x35, 0xe5, 0xbc, 0x82, 0x4d, 0x43, 0xb5, 0x08, 0xe7, + 0x1a, 0x67, 0x69, 0xfe, 0xa4, 0x12, 0xeb, 0x3c, 0x03, 0xd5, 0x79, 0x06, 0x1c, 0x58, 0xd7, 0x3b, + 0x5f, 0x23, 0xbf, 0x23, 0xba, 0x2f, 0x0b, 0x47, 0x5e, 0xa3, 0x3e, 0xfc, 0x29, 0xd4, 0x51, 0x44, + 0x6a, 0x8e, 0x30, 0x33, 0x03, 0xae, 0x12, 0xaf, 0x30, 0xf8, 0xaa, 0x30, 0x78, 0x9a, 0x29, 0x83, + 0xef, 0x79, 0x96, 0xf3, 0x61, 0xe1, 0xc6, 0x69, 0xc6, 0xef, 0xfa, 0xa2, 0x4f, 0x60, 0x4b, 0x2b, + 0x1d, 0x60, 0x88, 0x1c, 0xef, 0x08, 0xe9, 0x29, 0x90, 0x92, 0xda, 0x5d, 0xc7, 0x3d, 0x06, 0xeb, + 0xfc, 0xfc, 0xb8, 0x90, 0x96, 0xb1, 0xd1, 0xf9, 0x14, 0xb6, 0xce, 0x32, 0x3f, 0x3e, 0x65, 0xc1, + 0x4d, 0x10, 0xe2, 0x44, 0x19, 0xcb, 0x5f, 0x74, 0x15, 0xe3, 0x45, 0xb7, 0x72, 0x1a, 0x39, 0x03, + 0x20, 0xa5, 0xed, 0xc5, 0x77, 0x4b, 0x33, 0x3f, 0xd6, 0x2d, 0x2c, 0xd7, 0xce, 0x00, 0x3a, 0xe7, + 0x54, 0xcc, 0x7b, 0x5f, 0xe9, 0xd8, 0xd0, 0xe4, 0x8a, 0xd6, 0x6a, 0x39, 0xe9, 0x8c, 0x60, 0x7b, + 0x9f, 0x7a, 0x57, 0x41, 0x34, 0x39, 0x08, 0x52, 0x71, 0xe1, 0xd1, 0x3b, 0x7a, 0x60, 0xf9, 0x9a, + 0xa1, 0xb7, 0x14, 0xb4, 0xf3, 0x1c, 0xee, 0x1b, 0xef, 0xd6, 0x33, 0x4e, 0xf3, 0x7c, 0x6c, 0x43, + 0x3d, 0x15, 0x94, 0xdc, 0x51, 0x77, 0x15, 0xe1, 0x7c, 0x05, 0xdb, 0xe6, 0x00, 0x16, 0xd7, 0x8f, + 0x3c, 0x70, 0x79, 0x31, 0xa8, 0x18, 0x17, 0x03, 0x9d, 0xb3, 0xea, 0x7c, 0x9e, 0x6c, 0x42, 0xed, + 0x97, 0xdf, 0x9c, 0xeb, 0x62, 0x17, 0x4b, 0xe7, 0x77, 0xc2, 0x7c, 0xf9, 0x3c, 0x65, 0xbe, 0x74, + 0x3b, 0xa8, 0xbc, 0xcf, 0xed, 0x60, 0x45, 0xbd, 0x3d, 0x87, 0xad, 0x93, 0x30, 0xf6, 0xae, 0x0f, + 0x23, 0x23, 0x1b, 0x36, 0x34, 0x31, 0x32, 0x93, 0x91, 0x93, 0xce, 0x47, 0xb0, 0x71, 0x1c, 0x7b, + 0x34, 0x3c, 0x11, 0xcf, 0x8f, 0x22, 0x0b, 0xf2, 0x47, 0x82, 0x56, 0x55, 0x84, 0xf3, 0x1c, 0x60, + 0xfe, 0x84, 0x12, 0xf0, 0xcb, 0x70, 0x1a, 0x73, 0x1c, 0x53, 0xdf, 0xcf, 0x2b, 0x08, 0x14, 0x6b, + 0xcf, 0xf7, 0xd9, 0xe8, 0x9f, 0x55, 0x68, 0xfe, 0x42, 0x81, 0x1a, 0xf9, 0x0c, 0xba, 0xa5, 0x11, + 0x46, 0xee, 0xcb, 0x37, 0xd4, 0xe2, 0xc0, 0xec, 0x3d, 0x58, 0x62, 0x2b, 0x87, 0x5e, 0x40, 0xc7, + 0x1c, 0x50, 0x44, 0x0e, 0x23, 0xf9, 0x43, 0xa7, 0x27, 0x4f, 0x5a, 0x9e, 0x5e, 0x67, 0xb0, 0xbd, + 0x6a, 0x74, 0x90, 0xc7, 0x73, 0x0b, 0xcb, 0x63, 0xab, 0xf7, 0xc1, 0x5d, 0xd2, 0x7c, 0xe4, 0x34, + 0xf7, 0x43, 0xa4, 0x51, 0x96, 0x98, 0x1e, 0xcc, 0x97, 0xe4, 0x25, 0x74, 0x4b, 0xe0, 0xa9, 0xe2, + 0x5c, 0xc2, 0x53, 0x73, 0xcb, 0x53, 0xa8, 0x4b, 0xc0, 0x26, 0xdd, 0xd2, 0xe4, 0xe8, 0xad, 0x17, + 0xa4, 0xb2, 0xdd, 0x87, 0x35, 0xf9, 0x7c, 0x34, 0x0c, 0xcb, 0x1d, 0x05, 0x9a, 0x8f, 0xfe, 0x5e, + 0x81, 0x66, 0xfe, 0xeb, 0xe7, 0x25, 0xac, 0x09, 0x5c, 0x24, 0xf7, 0x0c, 0x68, 0xc9, 0x31, 0xb5, + 0xb7, 0xbd, 0xc0, 0x54, 0x06, 0x86, 0x50, 0x7b, 0x8d, 0x9c, 0x10, 0x43, 0xa8, 0x01, 0xb2, 0x77, + 0xaf, 0xcc, 0x2b, 0xf4, 0x4f, 0xb3, 0xb2, 0xbe, 0xc6, 0xb7, 0x92, 0x7e, 0x81, 0x5c, 0x3f, 0x81, + 0x86, 0x42, 0x1e, 0x95, 0x94, 0x25, 0xcc, 0x52, 0x1f, 0x7f, 0x19, 0xa3, 0x46, 0xff, 0xa8, 0x01, + 0x9c, 0xcd, 0x52, 0x8e, 0xd3, 0x5f, 0x05, 0x78, 0x4b, 0x9e, 0xc1, 0xc6, 0x01, 0x5e, 0xd2, 0x2c, + 0xe4, 0xf2, 0x05, 0x21, 0x3a, 0xcc, 0xc8, 0x89, 0xbc, 0x04, 0x15, 0x00, 0xf6, 0x14, 0xda, 0x27, + 0xf4, 0xed, 0xbb, 0xf5, 0x3e, 0x83, 0x6e, 0x09, 0x97, 0xb4, 0x8b, 0x8b, 0x48, 0xa7, 0x5d, 0x5c, + 0x46, 0xb0, 0xa7, 0xd0, 0xd4, 0x68, 0x65, 0xda, 0x90, 0xb8, 0x5e, 0x42, 0xb1, 0x1f, 0xc3, 0xc6, + 0x02, 0x56, 0x99, 0xfa, 0xf2, 0xf7, 0xd4, 0x4a, 0x2c, 0x7b, 0x25, 0x5e, 0x00, 0x65, 0xbc, 0x32, + 0x37, 0x3e, 0x54, 0x18, 0xb1, 0x0a, 0xd0, 0x5e, 0x97, 0xdf, 0x0e, 0xf2, 0xe5, 0x64, 0x2f, 0x42, + 0x4a, 0x0e, 0x68, 0xf9, 0x41, 0xab, 0xa0, 0xe9, 0x05, 0x74, 0x4c, 0x54, 0x59, 0x6a, 0xc1, 0x65, + 0xc8, 0xf9, 0x3e, 0xc0, 0x1c, 0x58, 0x4c, 0x7d, 0x59, 0x1e, 0x0b, 0x98, 0x73, 0xd1, 0x90, 0xaf, + 0x8d, 0x1f, 0xfc, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x7b, 0x3e, 0xd0, 0xf0, 0x15, 0x00, 0x00, } diff --git a/logical/plugin/pb/backend.proto b/logical/plugin/pb/backend.proto index db7c4a026e..d8f6dec868 100644 --- a/logical/plugin/pb/backend.proto +++ b/logical/plugin/pb/backend.proto @@ -212,6 +212,8 @@ message LeaseOptions { int64 increment = 3; google.protobuf.Timestamp issue_time = 4; + + int64 MaxTTL = 5; } message Secret { diff --git a/logical/plugin/pb/translation.go b/logical/plugin/pb/translation.go index 3d227ba45d..65d2cf7933 100644 --- a/logical/plugin/pb/translation.go +++ b/logical/plugin/pb/translation.go @@ -136,6 +136,7 @@ func ProtoLeaseOptionsToLogicalLeaseOptions(l *LeaseOptions) (logical.LeaseOptio Renewable: l.Renewable, Increment: time.Duration(l.Increment), IssueTime: t, + MaxTTL: time.Duration(l.MaxTTL), }, err } @@ -150,6 +151,7 @@ func LogicalLeaseOptionsToProtoLeaseOptions(l logical.LeaseOptions) (*LeaseOptio Renewable: l.Renewable, Increment: int64(l.Increment), IssueTime: t, + MaxTTL: int64(l.MaxTTL), }, err } diff --git a/logical/plugin/pb/translation_test.go b/logical/plugin/pb/translation_test.go index c55f36eac2..65bf400fcf 100644 --- a/logical/plugin/pb/translation_test.go +++ b/logical/plugin/pb/translation_test.go @@ -92,6 +92,7 @@ func TestTranslation_Request(t *testing.T) { Secret: &logical.Secret{ LeaseOptions: logical.LeaseOptions{ TTL: time.Second, + MaxTTL: time.Second, Renewable: true, Increment: time.Second, IssueTime: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), @@ -104,6 +105,7 @@ func TestTranslation_Request(t *testing.T) { Auth: &logical.Auth{ LeaseOptions: logical.LeaseOptions{ TTL: time.Second, + MaxTTL: time.Second, Renewable: true, Increment: time.Second, IssueTime: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), @@ -192,6 +194,7 @@ func TestTranslation_Response(t *testing.T) { Secret: &logical.Secret{ LeaseOptions: logical.LeaseOptions{ TTL: time.Second, + MaxTTL: time.Second, Renewable: true, Increment: time.Second, IssueTime: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), @@ -204,6 +207,7 @@ func TestTranslation_Response(t *testing.T) { Auth: &logical.Auth{ LeaseOptions: logical.LeaseOptions{ TTL: time.Second, + MaxTTL: time.Second, Renewable: true, Increment: time.Second, IssueTime: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), diff --git a/vault/core_test.go b/vault/core_test.go index a58fc3da75..b63ba822a4 100644 --- a/vault/core_test.go +++ b/vault/core_test.go @@ -381,7 +381,7 @@ func TestCore_HandleRequest_Lease_MaxLength(t *testing.T) { t.Fatalf("bad: %#v", resp) } if resp.Secret.TTL != c.maxLeaseTTL { - t.Fatalf("bad: %#v", resp.Secret) + t.Fatalf("bad: %#v, %d", resp.Secret, c.maxLeaseTTL) } if resp.Secret.LeaseID == "" { t.Fatalf("bad: %#v", resp.Secret) @@ -422,7 +422,7 @@ func TestCore_HandleRequest_Lease_DefaultLength(t *testing.T) { t.Fatalf("bad: %#v", resp) } if resp.Secret.TTL != c.defaultLeaseTTL { - t.Fatalf("bad: %#v", resp.Secret) + t.Fatalf("bad: %#v, %d", resp.Secret, c.defaultLeaseTTL) } if resp.Secret.LeaseID == "" { t.Fatalf("bad: %#v", resp.Secret) diff --git a/vault/dynamic_system_view.go b/vault/dynamic_system_view.go index e54e9f005e..06f9ac63b9 100644 --- a/vault/dynamic_system_view.go +++ b/vault/dynamic_system_view.go @@ -6,7 +6,6 @@ import ( "time" "github.com/hashicorp/errwrap" - "github.com/hashicorp/vault/helper/consts" "github.com/hashicorp/vault/helper/pluginutil" "github.com/hashicorp/vault/helper/wrapping" diff --git a/vault/expiration.go b/vault/expiration.go index d9b0f76405..9f3b3c44d4 100644 --- a/vault/expiration.go +++ b/vault/expiration.go @@ -21,6 +21,7 @@ import ( "github.com/hashicorp/vault/helper/jsonutil" "github.com/hashicorp/vault/helper/locksutil" "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" ) const ( @@ -640,21 +641,36 @@ func (m *ExpirationManager) Renew(leaseID string, increment time.Duration) (*log return logical.ErrorResponse("lease does not correspond to a secret"), nil } + sysView := m.router.MatchingSystemView(le.Path) + if sysView == nil { + return nil, fmt.Errorf("expiration: unable to retrieve system view from router") + } + // Attempt to renew the entry resp, err := m.renewEntry(le, increment) if err != nil { return nil, err } - - // Fast-path if there is no lease - if resp == nil || resp.Secret == nil || !resp.Secret.LeaseEnabled() { - return resp, nil + if resp == nil { + return nil, nil + } + if resp.IsError() { + return &logical.Response{ + Data: resp.Data, + }, nil + } + if resp.Secret == nil { + return nil, nil } - // Validate the lease - if err := resp.Secret.Validate(); err != nil { + ttl, warnings, err := framework.CalculateTTL(sysView, increment, resp.Secret.TTL, 0, resp.Secret.MaxTTL, 0, le.IssueTime) + if err != nil { return nil, err } + for _, warning := range warnings { + resp.AddWarning(warning) + } + resp.Secret.TTL = ttl // Attach the LeaseID resp.Secret.LeaseID = leaseID @@ -744,21 +760,16 @@ func (m *ExpirationManager) RenewToken(req *logical.Request, source string, toke if err != nil { return nil, err } - if resp == nil { return nil, nil } - if resp.IsError() { return &logical.Response{ Data: resp.Data, }, nil } - - if resp.Auth == nil || !resp.Auth.LeaseEnabled() { - return &logical.Response{ - Auth: resp.Auth, - }, nil + if resp.Auth == nil { + return nil, nil } sysView := m.router.MatchingSystemView(le.Path) @@ -766,29 +777,18 @@ func (m *ExpirationManager) RenewToken(req *logical.Request, source string, toke return nil, fmt.Errorf("expiration: unable to retrieve system view from router") } - retResp := &logical.Response{} - switch { - case resp.Auth.Period > time.Duration(0): - // If it resp.Period is non-zero, use that as the TTL and override backend's - // call on TTL modification, such as a TTL value determined by - // framework.LeaseExtend call against the request. Also, cap period value to - // the sys/mount max value. - if resp.Auth.Period > sysView.MaxLeaseTTL() { - retResp.AddWarning(fmt.Sprintf("Period of %d seconds is greater than current mount/system default of %d seconds, value will be truncated.", int64(resp.Auth.TTL.Seconds()), int64(sysView.MaxLeaseTTL().Seconds()))) - resp.Auth.Period = sysView.MaxLeaseTTL() - } - resp.Auth.TTL = resp.Auth.Period - case resp.Auth.TTL > time.Duration(0): - // Cap TTL value to the sys/mount max value - if resp.Auth.TTL > sysView.MaxLeaseTTL() { - retResp.AddWarning(fmt.Sprintf("TTL of %d seconds is greater than current mount/system default of %d seconds, value will be truncated.", int64(resp.Auth.TTL.Seconds()), int64(sysView.MaxLeaseTTL().Seconds()))) - resp.Auth.TTL = sysView.MaxLeaseTTL() - } + ttl, warnings, err := framework.CalculateTTL(sysView, increment, resp.Auth.TTL, resp.Auth.Period, resp.Auth.MaxTTL, resp.Auth.ExplicitMaxTTL, le.IssueTime) + if err != nil { + return nil, err } + retResp := &logical.Response{} + for _, warning := range warnings { + retResp.AddWarning(warning) + } + resp.Auth.TTL = ttl // Attach the ClientToken resp.Auth.ClientToken = token - resp.Auth.Increment = 0 // Update the lease entry le.Auth = resp.Auth @@ -902,12 +902,6 @@ func (m *ExpirationManager) RegisterAuth(source string, auth *logical.Auth) erro return err } - // If it resp.Period is non-zero, override the TTL value determined - // by the backend. - if auth.Period > time.Duration(0) { - auth.TTL = auth.Period - } - // Create a lease entry le := leaseEntry{ LeaseID: path.Join(source, saltedID), @@ -1069,7 +1063,6 @@ func (m *ExpirationManager) renewEntry(le *leaseEntry, increment time.Duration) secret.IssueTime = le.IssueTime secret.Increment = increment secret.LeaseID = "" - req := logical.RenewRequest(le.Path, &secret, le.Data) resp, err := m.router.Route(m.quitContext, req) if err != nil || (resp != nil && resp.IsError()) { diff --git a/vault/expiration_test.go b/vault/expiration_test.go index fbe7d08683..2e932b7271 100644 --- a/vault/expiration_test.go +++ b/vault/expiration_test.go @@ -796,8 +796,14 @@ func TestExpiration_RenewToken(t *testing.T) { func TestExpiration_RenewToken_period(t *testing.T) { exp := mockExpiration(t) - root, err := exp.tokenStore.rootToken(context.Background()) - if err != nil { + root := &TokenEntry{ + Policies: []string{"root"}, + Path: "auth/token/root", + DisplayName: "root", + CreationTime: time.Now().Unix(), + Period: time.Minute, + } + if err := exp.tokenStore.create(context.Background(), root); err != nil { t.Fatalf("err: %v", err) } @@ -810,7 +816,7 @@ func TestExpiration_RenewToken_period(t *testing.T) { }, Period: time.Minute, } - err = exp.RegisterAuth("auth/token/login", auth) + err := exp.RegisterAuth("auth/token/login", auth) if err != nil { t.Fatalf("err: %v", err) } @@ -869,7 +875,6 @@ func TestExpiration_RenewToken_period_backend(t *testing.T) { LeaseOptions: logical.LeaseOptions{ TTL: 10 * time.Second, Renewable: true, - IssueTime: time.Now(), }, Period: 5 * time.Second, } @@ -888,8 +893,8 @@ func TestExpiration_RenewToken_period_backend(t *testing.T) { if resp == nil { t.Fatal("expected a response") } - if resp.Auth.TTL > 5*time.Second { - t.Fatalf("expected TTL to be less than or equal to period, got: %s", resp.Auth.TTL) + if resp.Auth.TTL == 0 || resp.Auth.TTL > 5*time.Second { + t.Fatalf("expected TTL to be greater than zero and less than or equal to period, got: %s", resp.Auth.TTL) } // Wait another 3 seconds. If period works correctly, this should not fail @@ -1293,7 +1298,7 @@ func TestExpiration_renewEntry(t *testing.T) { ExpireTime: time.Now(), } - resp, err := exp.renewEntry(le, time.Second) + resp, err := exp.renewEntry(le) if err != nil { t.Fatalf("err: %v", err) } @@ -1312,12 +1317,6 @@ func TestExpiration_renewEntry(t *testing.T) { if !reflect.DeepEqual(req.Data, le.Data) { t.Fatalf("Bad: %v", req) } - if req.Secret.Increment != time.Second { - t.Fatalf("Bad: %v", req) - } - if req.Secret.IssueTime.IsZero() { - t.Fatalf("Bad: %v", req) - } } func TestExpiration_renewAuthEntry(t *testing.T) { @@ -1360,7 +1359,7 @@ func TestExpiration_renewAuthEntry(t *testing.T) { ExpireTime: time.Now().Add(time.Minute), } - resp, err := exp.renewAuthEntry(&logical.Request{}, le, time.Second) + resp, err := exp.renewAuthEntry(&logical.Request{}, le) if err != nil { t.Fatalf("err: %v", err) } @@ -1379,12 +1378,6 @@ func TestExpiration_renewAuthEntry(t *testing.T) { if req.Path != "login" { t.Fatalf("Bad: %v", req) } - if req.Auth.Increment != time.Second { - t.Fatalf("Bad: %v", req) - } - if req.Auth.IssueTime.IsZero() { - t.Fatalf("Bad: %v", req) - } if req.Auth.InternalData["MySecret"] != "secret" { t.Fatalf("Bad: %v", req) } diff --git a/vault/request_handling.go b/vault/request_handling.go index c360778f5a..7785a76856 100644 --- a/vault/request_handling.go +++ b/vault/request_handling.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/vault/helper/strutil" "github.com/hashicorp/vault/helper/wrapping" "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" ) const ( @@ -290,25 +291,6 @@ func (c *Core) handleRequest(ctx context.Context, req *logical.Request) (retResp // We exclude renewal of a lease, since it does not need to be re-registered if resp != nil && resp.Secret != nil && !strings.HasPrefix(req.Path, "sys/renew") && !strings.HasPrefix(req.Path, "sys/leases/renew") { - // Get the SystemView for the mount - sysView := c.router.MatchingSystemView(req.Path) - if sysView == nil { - c.logger.Error("unable to retrieve system view from router") - retErr = multierror.Append(retErr, ErrInternalError) - return nil, auth, retErr - } - - // Apply the default lease if none given - if resp.Secret.TTL == 0 { - resp.Secret.TTL = sysView.DefaultLeaseTTL() - } - - // Limit the lease duration - maxTTL := sysView.MaxLeaseTTL() - if resp.Secret.TTL > maxTTL { - resp.Secret.TTL = maxTTL - } - // KV mounts should return the TTL but not register // for a lease as this provides a massive slowdown registerLease := true @@ -351,6 +333,21 @@ func (c *Core) handleRequest(ctx context.Context, req *logical.Request) (retResp } if registerLease { + sysView := c.router.MatchingSystemView(req.Path) + if sysView == nil { + c.logger.Error("core: unable to look up sys view for login path", "request_path", req.Path) + return nil, nil, ErrInternalError + } + + ttl, warnings, err := framework.CalculateTTL(sysView, 0, resp.Secret.TTL, 0, resp.Secret.MaxTTL, 0, time.Time{}) + if err != nil { + return nil, nil, err + } + for _, warning := range warnings { + resp.AddWarning(warning) + } + resp.Secret.TTL = ttl + leaseID, err := c.expiration.Register(req, resp) if err != nil { c.logger.Error("failed to register lease", "request_path", req.Path, "error", err) @@ -549,27 +546,12 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re return nil, nil, ErrInternalError } - // Start off with the sys default value, and update according to period/TTL - // from resp.Auth - tokenTTL := sysView.DefaultLeaseTTL() - - switch { - case auth.Period > time.Duration(0): - // Cap the period value to the sys max_ttl value. The auth backend should - // have checked for it on its login path, but we check here again for - // sanity. - if auth.Period > sysView.MaxLeaseTTL() { - auth.Period = sysView.MaxLeaseTTL() - } - tokenTTL = auth.Period - case auth.TTL > time.Duration(0): - // Cap the TTL value. The auth backend should have checked for it on its - // login path (e.g. a call to b.SanitizeTTL), but we check here again for - // sanity. - if auth.TTL > sysView.MaxLeaseTTL() { - auth.TTL = sysView.MaxLeaseTTL() - } - tokenTTL = auth.TTL + tokenTTL, warnings, err := framework.CalculateTTL(sysView, 0, auth.TTL, auth.Period, auth.MaxTTL, auth.ExplicitMaxTTL, time.Time{}) + if err != nil { + return nil, nil, err + } + for _, warning := range warnings { + resp.AddWarning(warning) } // Generate a token diff --git a/vault/token_store.go b/vault/token_store.go index 9377d474cf..24d92cefdc 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -766,11 +766,11 @@ func (ts *TokenStore) create(ctx context.Context, entry *TokenEntry) error { entry.ID = entryUUID } - saltedId, err := ts.SaltID(ctx, entry.ID) + saltedID, err := ts.SaltID(ctx, entry.ID) if err != nil { return err } - exist, _ := ts.lookupSalted(ctx, saltedId, true) + exist, _ := ts.lookupSalted(ctx, saltedID, true) if exist != nil { return fmt.Errorf("cannot create a token with a duplicate ID") } @@ -795,7 +795,7 @@ func (ts *TokenStore) store(ctx context.Context, entry *TokenEntry) error { // storeCommon handles the actual storage of an entry, possibly generating // secondary indexes func (ts *TokenStore) storeCommon(ctx context.Context, entry *TokenEntry, writeSecondary bool) error { - saltedId, err := ts.SaltID(ctx, entry.ID) + saltedID, err := ts.SaltID(ctx, entry.ID) if err != nil { return err } @@ -826,7 +826,7 @@ func (ts *TokenStore) storeCommon(ctx context.Context, entry *TokenEntry, writeS if err != nil { return err } - path := parentPrefix + parentSaltedID + "/" + saltedId + path := parentPrefix + parentSaltedID + "/" + saltedID le := &logical.StorageEntry{Key: path} if err := ts.view.Put(ctx, le); err != nil { return fmt.Errorf("failed to persist entry: %v", err) @@ -835,7 +835,7 @@ func (ts *TokenStore) storeCommon(ctx context.Context, entry *TokenEntry, writeS } // Write the primary ID - path := lookupPrefix + saltedId + path := lookupPrefix + saltedID le := &logical.StorageEntry{Key: path, Value: enc} if len(entry.Policies) == 1 && entry.Policies[0] == "root" { le.SealWrap = true @@ -1060,11 +1060,11 @@ func (ts *TokenStore) Revoke(ctx context.Context, id string) error { // revokeSalted is used to invalidate a given salted token, // any child tokens will be orphaned. -func (ts *TokenStore) revokeSalted(ctx context.Context, saltedId string) (ret error) { +func (ts *TokenStore) revokeSalted(ctx context.Context, saltedID string) (ret error) { // Protect the entry lookup/writing with locks. The rub here is that we // don't know the ID until we look it up once, so first we look it up, then // do a locked lookup. - entry, err := ts.lookupSalted(ctx, saltedId, true) + entry, err := ts.lookupSalted(ctx, saltedID, true) if err != nil { return err } @@ -1076,7 +1076,7 @@ func (ts *TokenStore) revokeSalted(ctx context.Context, saltedId string) (ret er lock.Lock() // Lookup the token first - entry, err = ts.lookupSalted(ctx, saltedId, true) + entry, err = ts.lookupSalted(ctx, saltedID, true) if err != nil { lock.Unlock() return err @@ -1116,7 +1116,7 @@ func (ts *TokenStore) revokeSalted(ctx context.Context, saltedId string) (ret er // Lookup the token again to make sure something else didn't // revoke in the interim - entry, err := ts.lookupSalted(ctx, saltedId, true) + entry, err := ts.lookupSalted(ctx, saltedID, true) if err != nil { return } @@ -1132,7 +1132,7 @@ func (ts *TokenStore) revokeSalted(ctx context.Context, saltedId string) (ret er // Destroy the token's cubby. This should go first as it's a // security-sensitive item. - err = ts.cubbyholeDestroyer(ctx, ts, saltedId) + err = ts.cubbyholeDestroyer(ctx, ts, saltedID) if err != nil { return err } @@ -1150,7 +1150,7 @@ func (ts *TokenStore) revokeSalted(ctx context.Context, saltedId string) (ret er return err } - path := parentPrefix + parentSaltedID + "/" + saltedId + path := parentPrefix + parentSaltedID + "/" + saltedID if err = ts.view.Delete(ctx, path); err != nil { return fmt.Errorf("failed to delete entry: %v", err) } @@ -1177,7 +1177,7 @@ func (ts *TokenStore) revokeSalted(ctx context.Context, saltedId string) (ret er // explicit call to orphan the child tokens (the delete occurs at the leaf // node and uses parent prefix, not entry.Parent, to build the tree for // traversal). - parentPath := parentPrefix + saltedId + "/" + parentPath := parentPrefix + saltedID + "/" children, err := ts.view.List(ctx, parentPath) if err != nil { return fmt.Errorf("failed to scan for children: %v", err) @@ -1203,7 +1203,7 @@ func (ts *TokenStore) revokeSalted(ctx context.Context, saltedId string) (ret er } // Now that the entry is not usable for any revocation tasks, nuke it - path := lookupPrefix + saltedId + path := lookupPrefix + saltedID if err = ts.view.Delete(ctx, path); err != nil { return fmt.Errorf("failed to delete entry: %v", err) } @@ -1221,25 +1221,22 @@ func (ts *TokenStore) RevokeTree(ctx context.Context, id string) error { } // Get the salted ID - saltedId, err := ts.SaltID(ctx, id) + saltedID, err := ts.SaltID(ctx, id) if err != nil { return err } // Nuke the entire tree recursively - if err := ts.revokeTreeSalted(ctx, saltedId); err != nil { - return err - } - return nil + return ts.revokeTreeSalted(ctx, saltedID) } // revokeTreeSalted is used to invalidate a given token and all // child tokens using a saltedID. // Updated to be non-recursive and revoke child tokens // before parent tokens(DFS). -func (ts *TokenStore) revokeTreeSalted(ctx context.Context, saltedId string) error { +func (ts *TokenStore) revokeTreeSalted(ctx context.Context, saltedID string) error { var dfs []string - dfs = append(dfs, saltedId) + dfs = append(dfs, saltedID) for l := len(dfs); l > 0; l = len(dfs) { id := dfs[0] @@ -1467,13 +1464,13 @@ func (ts *TokenStore) handleTidy(ctx context.Context, req *logical.Request, data // Look up tainted variants so we only find entries that truly don't // exist - saltedId, err := ts.SaltID(ctx, accessorEntry.TokenID) + saltedID, err := ts.SaltID(ctx, accessorEntry.TokenID) if err != nil { tidyErrors = multierror.Append(tidyErrors, fmt.Errorf("failed to read salt id: %v", err)) lock.RUnlock() continue } - te, err := ts.lookupSalted(ctx, saltedId, true) + te, err := ts.lookupSalted(ctx, saltedID, true) if err != nil { tidyErrors = multierror.Append(tidyErrors, fmt.Errorf("failed to lookup tainted ID: %v", err)) lock.RUnlock() @@ -1486,7 +1483,7 @@ func (ts *TokenStore) handleTidy(ctx context.Context, req *logical.Request, data // more and conclude that accessor, leases, and secondary index entries // for this token should not exist as well. if te == nil { - ts.logger.Info("deleting token with nil entry", "salted_token", saltedId) + ts.logger.Info("deleting token with nil entry", "salted_token", saltedID) // RevokeByToken expects a '*TokenEntry'. For the // purposes of tidying, it is sufficient if the token @@ -1884,6 +1881,7 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque te.EntityID = parent.EntityID } + var explicitMaxTTLToUse time.Duration if data.ExplicitMaxTTL != "" { dur, err := parseutil.ParseDurationSecond(data.ExplicitMaxTTL) if err != nil { @@ -1893,6 +1891,7 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque return logical.ErrorResponse("explicit_max_ttl must be positive"), logical.ErrInvalidRequest } te.ExplicitMaxTTL = dur + explicitMaxTTLToUse = dur } var periodToUse time.Duration @@ -1942,13 +1941,13 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque if role != nil { if role.ExplicitMaxTTL != 0 { switch { - case te.ExplicitMaxTTL == 0: - te.ExplicitMaxTTL = role.ExplicitMaxTTL + case explicitMaxTTLToUse == 0: + explicitMaxTTLToUse = role.ExplicitMaxTTL default: - if role.ExplicitMaxTTL < te.ExplicitMaxTTL { - te.ExplicitMaxTTL = role.ExplicitMaxTTL + if role.ExplicitMaxTTL < explicitMaxTTLToUse { + explicitMaxTTLToUse = role.ExplicitMaxTTL } - resp.AddWarning(fmt.Sprintf("Explicit max TTL specified both during creation call and in role; using the lesser value of %d seconds", int64(te.ExplicitMaxTTL.Seconds()))) + resp.AddWarning(fmt.Sprintf("Explicit max TTL specified both during creation call and in role; using the lesser value of %d seconds", int64(explicitMaxTTLToUse.Seconds()))) } } if role.Period != 0 { @@ -1966,49 +1965,21 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque sysView := ts.System() - if periodToUse > 0 { - // Cap period value to the sys/mount max value; this matches behavior - // in expiration manager for renewals - if periodToUse > sysView.MaxLeaseTTL() { - resp.AddWarning(fmt.Sprintf("Period of %d seconds is greater than current mount/system default of %d seconds, value will be truncated.", int64(periodToUse.Seconds()), int64(sysView.MaxLeaseTTL().Seconds()))) - periodToUse = sysView.MaxLeaseTTL() + // Only calculate a TTL if you are A) periodic, B) have a TTL, C) do not have a TTL and are not a root token + if periodToUse > 0 || te.TTL > 0 || (te.TTL == 0 && !strutil.StrListContains(te.Policies, "root")) { + ttl, warnings, err := framework.CalculateTTL(sysView, 0, te.TTL, periodToUse, 0, explicitMaxTTLToUse, time.Unix(te.CreationTime, 0)) + if err != nil { + return nil, err } - te.TTL = periodToUse - } else { - // Set the default lease if not provided, root tokens are exempt - if te.TTL == 0 && !strutil.StrListContains(te.Policies, "root") { - te.TTL = sysView.DefaultLeaseTTL() - } - - // Limit the lease duration - if te.TTL > sysView.MaxLeaseTTL() && sysView.MaxLeaseTTL() != 0 { - te.TTL = sysView.MaxLeaseTTL() + for _, warning := range warnings { + resp.AddWarning(warning) } + te.TTL = ttl } - // Run some bounding checks if the explicit max TTL is set; we do not check - // period as it's defined to escape the max TTL - if te.ExplicitMaxTTL > 0 { - // Limit the lease duration, except for periodic tokens -- in that case the explicit max limits the period, which itself can escape normal max - if sysView.MaxLeaseTTL() != 0 && te.ExplicitMaxTTL > sysView.MaxLeaseTTL() && periodToUse == 0 { - resp.AddWarning(fmt.Sprintf( - "Explicit max TTL of %d seconds is greater than system/mount allowed value; value is being capped to %d seconds", - int64(te.ExplicitMaxTTL.Seconds()), int64(sysView.MaxLeaseTTL().Seconds()))) - te.ExplicitMaxTTL = sysView.MaxLeaseTTL() - } - - if te.TTL == 0 { - // This won't be the case if it's periodic -- it will be set above - te.TTL = te.ExplicitMaxTTL - } else { - // Limit even in the periodic case - if te.TTL > te.ExplicitMaxTTL { - resp.AddWarning(fmt.Sprintf( - "Requested TTL of %d seconds higher than explicit max TTL; value being capped to %d seconds", - int64(te.TTL.Seconds()), int64(te.ExplicitMaxTTL.Seconds()))) - te.TTL = te.ExplicitMaxTTL - } - } + // Root tokens are still bound by explicit max TTL + if te.TTL == 0 && explicitMaxTTLToUse > 0 { + te.TTL = explicitMaxTTLToUse } // Don't advertise non-expiring root tokens as renewable, as attempts to renew them are denied @@ -2034,9 +2005,11 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque TTL: te.TTL, Renewable: renewable, }, - ClientToken: te.ID, - Accessor: te.Accessor, - EntityID: te.EntityID, + ClientToken: te.ID, + Accessor: te.Accessor, + EntityID: te.EntityID, + Period: periodToUse, + ExplicitMaxTTL: explicitMaxTTLToUse, } if ts.policyLookupFunc != nil { @@ -2166,11 +2139,11 @@ func (ts *TokenStore) handleLookup(ctx context.Context, req *logical.Request, da defer lock.RUnlock() // Lookup the token - saltedId, err := ts.SaltID(ctx, id) + saltedID, err := ts.SaltID(ctx, id) if err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } - out, err := ts.lookupSalted(ctx, saltedId, true) + out, err := ts.lookupSalted(ctx, saltedID, true) if err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } @@ -2301,68 +2274,23 @@ func (ts *TokenStore) authRenew(ctx context.Context, req *logical.Request, d *fr return nil, fmt.Errorf("no token entry found during lookup") } - f := framework.LeaseExtend(req.Auth.Increment, te.ExplicitMaxTTL, ts.System()) - - // If (te/role).Period is not zero, this is a periodic token. The TTL for a - // periodic token is always the same (the period value). It is not subject - // to normal maximum TTL checks that would come from calling LeaseExtend, - // so we fast path it. - // - // The one wrinkle here is if the token has an explicit max TTL. If both - // are set, we treat it as a regular token and use the periodic value as - // the increment. - - // No role? Use normal LeaseExtend semantics, taking into account - // TokenEntry properties if te.Role == "" { - //Explicit max TTL overrides the period, if both are set - if te.Period != 0 { - if te.ExplicitMaxTTL == 0 { - req.Auth.TTL = te.Period - return &logical.Response{Auth: req.Auth}, nil - } else { - maxTime := time.Unix(te.CreationTime, 0).Add(te.ExplicitMaxTTL) - if time.Now().Add(te.Period).After(maxTime) { - req.Auth.TTL = maxTime.Sub(time.Now()) - } else { - req.Auth.TTL = te.Period - } - return &logical.Response{Auth: req.Auth}, nil - } - } - return f(ctx, req, d) + req.Auth.Period = te.Period + req.Auth.ExplicitMaxTTL = te.ExplicitMaxTTL + return &logical.Response{Auth: req.Auth}, nil } role, err := ts.tokenStoreRole(ctx, te.Role) if err != nil { return nil, fmt.Errorf("error looking up role %s: %s", te.Role, err) } - if role == nil { return nil, fmt.Errorf("original token role (%s) could not be found, not renewing", te.Role) } - // Same deal here, but using the role period - if role.Period != 0 { - periodToUse := role.Period - if te.Period > 0 && te.Period < role.Period { - periodToUse = te.Period - } - if te.ExplicitMaxTTL == 0 { - req.Auth.TTL = periodToUse - return &logical.Response{Auth: req.Auth}, nil - } else { - maxTime := time.Unix(te.CreationTime, 0).Add(te.ExplicitMaxTTL) - if time.Now().Add(periodToUse).After(maxTime) { - req.Auth.TTL = maxTime.Sub(time.Now()) - } else { - req.Auth.TTL = periodToUse - } - return &logical.Response{Auth: req.Auth}, nil - } - } - - return f(ctx, req, d) + req.Auth.Period = role.Period + req.Auth.ExplicitMaxTTL = role.ExplicitMaxTTL + return &logical.Response{Auth: req.Auth}, nil } func (ts *TokenStore) tokenStoreRole(ctx context.Context, name string) (*tsRoleEntry, error) { diff --git a/vault/token_store_test.go b/vault/token_store_test.go index f933caed87..3e6cf74c9f 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -59,11 +59,11 @@ func TestTokenStore_TokenEntryUpgrade(t *testing.T) { t.Fatal(err) } - saltedId, err := ts.SaltID(context.Background(), entry.ID) + saltedID, err := ts.SaltID(context.Background(), entry.ID) if err != nil { t.Fatal(err) } - path := lookupPrefix + saltedId + path := lookupPrefix + saltedID le := &logical.StorageEntry{ Key: path, Value: enc, @@ -2381,7 +2381,7 @@ func TestTokenStore_RolePeriod(t *testing.T) { } ttl = resp.Data["ttl"].(int64) if ttl > 8 { - t.Fatalf("TTL too large") + t.Fatalf("TTL too large: %d", ttl) } // Renewing should not have the increment increase since we've hit the @@ -2596,9 +2596,10 @@ func TestTokenStore_RoleExplicitMaxTTL(t *testing.T) { if ttl > 10 { t.Fatalf("TTL too big") } + // explicit max ttl is stored in the role so not returned here maxTTL := resp.Data["explicit_max_ttl"].(int64) - if maxTTL != 10 { - t.Fatalf("expected 6 for explicit max TTL, got %d", maxTTL) + if maxTTL != 0 { + t.Fatalf("expected 0 for explicit max TTL, got %d", maxTTL) } // Let the TTL go down a bit to ~7 seconds (8 against explicit max) @@ -2622,7 +2623,7 @@ func TestTokenStore_RoleExplicitMaxTTL(t *testing.T) { } ttl = resp.Data["ttl"].(int64) if ttl > 8 { - t.Fatalf("TTL too big") + t.Fatalf("TTL too big: %d", ttl) } // Let the TTL go down a bit more to ~5 seconds (6 against explicit max) @@ -2755,7 +2756,92 @@ func TestTokenStore_Periodic(t *testing.T) { } } - // Do the same with an explicit max TTL + // Now we create a token against the role and also set the te value + // directly. We should use the smaller of the two and be able to renew; + // increment should be ignored as well. + { + req.ClientToken = root + req.Operation = logical.UpdateOperation + req.Path = "auth/token/create/test" + req.Data = map[string]interface{}{ + "period": 5, + } + resp, err = core.HandleRequest(req) + if err != nil { + t.Fatalf("err: %v %v", err, resp) + } + if resp == nil { + t.Fatal("response was nil") + } + if resp.Auth == nil { + t.Fatalf(fmt.Sprintf("response auth was nil, resp is %#v", *resp)) + } + if resp.Auth.ClientToken == "" { + t.Fatalf("bad: %#v", resp) + } + + req.ClientToken = resp.Auth.ClientToken + req.Operation = logical.ReadOperation + req.Path = "auth/token/lookup-self" + resp, err = core.HandleRequest(req) + if err != nil { + t.Fatalf("err: %v", err) + } + ttl := resp.Data["ttl"].(int64) + if ttl < 4 || ttl > 5 { + t.Fatalf("TTL bad (expected %d, got %d)", 4, ttl) + } + + // Let the TTL go down a bit + time.Sleep(2 * time.Second) + + req.Operation = logical.UpdateOperation + req.Path = "auth/token/renew-self" + req.Data = map[string]interface{}{ + "increment": 1, + } + resp, err = core.HandleRequest(req) + if err != nil { + t.Fatalf("err: %v %v", err, resp) + } + + req.Operation = logical.ReadOperation + req.Path = "auth/token/lookup-self" + resp, err = core.HandleRequest(req) + if err != nil { + t.Fatalf("err: %v", err) + } + ttl = resp.Data["ttl"].(int64) + if ttl > 5 { + t.Fatalf("TTL bad (expected less than %d, got %d)", 5, ttl) + } + } +} + +func TestTokenStore_Periodic_ExplicitMax(t *testing.T) { + core, _, _, root := TestCoreWithTokenStore(t) + + core.defaultLeaseTTL = 10 * time.Second + core.maxLeaseTTL = 10 * time.Second + + // Note: these requests are sent to Core since Core handles registration + // with the expiration manager and we need the storage to be consistent + + req := logical.TestRequest(t, logical.UpdateOperation, "auth/token/roles/test") + req.ClientToken = root + req.Data = map[string]interface{}{ + "period": 5, + } + + resp, err := core.HandleRequest(req) + if err != nil { + t.Fatalf("err: %v %v", err, resp) + } + if resp != nil { + t.Fatalf("expected a nil response") + } + + // First make one directly and verify on renew it uses the period. { req.ClientToken = root req.Operation = logical.UpdateOperation @@ -2818,65 +2904,6 @@ func TestTokenStore_Periodic(t *testing.T) { // Now we create a token against the role and also set the te value // directly. We should use the smaller of the two and be able to renew; // increment should be ignored as well. - { - req.ClientToken = root - req.Operation = logical.UpdateOperation - req.Path = "auth/token/create/test" - req.Data = map[string]interface{}{ - "period": 5, - } - resp, err = core.HandleRequest(req) - if err != nil { - t.Fatalf("err: %v %v", err, resp) - } - if resp == nil { - t.Fatal("response was nil") - } - if resp.Auth == nil { - t.Fatalf(fmt.Sprintf("response auth was nil, resp is %#v", *resp)) - } - if resp.Auth.ClientToken == "" { - t.Fatalf("bad: %#v", resp) - } - - req.ClientToken = resp.Auth.ClientToken - req.Operation = logical.ReadOperation - req.Path = "auth/token/lookup-self" - resp, err = core.HandleRequest(req) - if err != nil { - t.Fatalf("err: %v", err) - } - ttl := resp.Data["ttl"].(int64) - if ttl < 4 || ttl > 5 { - t.Fatalf("TTL bad (expected %d, got %d)", 4, ttl) - } - - // Let the TTL go down a bit - time.Sleep(2 * time.Second) - - req.Operation = logical.UpdateOperation - req.Path = "auth/token/renew-self" - req.Data = map[string]interface{}{ - "increment": 1, - } - resp, err = core.HandleRequest(req) - if err != nil { - t.Fatalf("err: %v %v", err, resp) - } - - req.Operation = logical.ReadOperation - req.Path = "auth/token/lookup-self" - resp, err = core.HandleRequest(req) - if err != nil { - t.Fatalf("err: %v", err) - } - ttl = resp.Data["ttl"].(int64) - if ttl > 5 { - t.Fatalf("TTL bad (expected less than %d, got %d)", 5, ttl) - } - } - - // Now do the same, also using an explicit max in the role { req.Path = "auth/token/roles/test" req.ClientToken = root