From 5960112e6f24610a0d7a7d2a92a72b725943568a Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Thu, 18 Jan 2018 01:25:36 -0500 Subject: [PATCH] Fix max_ttl not being honored in database backend when default_ttl is zero Fixes #3812 --- builtin/logical/database/backend_test.go | 74 ++++++++++++++++++- builtin/logical/database/path_creds_create.go | 9 ++- builtin/logical/mongodb/path_creds_create.go | 8 +- builtin/logical/mssql/path_creds_create.go | 8 +- builtin/logical/mysql/path_role_create.go | 8 +- .../logical/postgresql/path_role_create.go | 9 ++- builtin/logical/rabbitmq/path_role_create.go | 7 +- 7 files changed, 112 insertions(+), 11 deletions(-) diff --git a/builtin/logical/database/backend_test.go b/builtin/logical/database/backend_test.go index 5122e0d823ad..97dc8e5d8fdb 100644 --- a/builtin/logical/database/backend_test.go +++ b/builtin/logical/database/backend_test.go @@ -9,6 +9,7 @@ import ( "reflect" "sync" "testing" + "time" "github.com/hashicorp/vault/builtin/logical/database/dbplugin" "github.com/hashicorp/vault/helper/pluginutil" @@ -270,7 +271,6 @@ func TestBackend_basic(t *testing.T) { data = map[string]interface{}{ "db_name": "plugin-test", "creation_statements": testRole, - "default_ttl": "5m", "max_ttl": "10m", } req = &logical.Request{ @@ -283,7 +283,6 @@ func TestBackend_basic(t *testing.T) { if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%s resp:%#v\n", err, resp) } - // Get creds data = map[string]interface{}{} req = &logical.Request{ @@ -296,7 +295,76 @@ func TestBackend_basic(t *testing.T) { if err != nil || (credsResp != nil && credsResp.IsError()) { t.Fatalf("err:%s resp:%#v\n", err, credsResp) } - + // Test for #3812 + if credsResp.Secret.TTL != 10*time.Minute { + t.Fatalf("unexpected TTL of %d", credsResp.Secret.TTL) + } + // Update the role with no max ttl + data = map[string]interface{}{ + "db_name": "plugin-test", + "creation_statements": testRole, + "default_ttl": "5m", + "max_ttl": 0, + } + req = &logical.Request{ + Operation: logical.UpdateOperation, + Path: "roles/plugin-role-test", + Storage: config.StorageView, + Data: data, + } + resp, err = b.HandleRequest(context.Background(), req) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } + // Get creds + data = map[string]interface{}{} + req = &logical.Request{ + Operation: logical.ReadOperation, + Path: "creds/plugin-role-test", + Storage: config.StorageView, + Data: data, + } + credsResp, err = b.HandleRequest(context.Background(), req) + if err != nil || (credsResp != nil && credsResp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, credsResp) + } + // Test for #3812 + if credsResp.Secret.TTL != 5*time.Minute { + t.Fatalf("unexpected TTL of %d", credsResp.Secret.TTL) + } + // Update the role with a max ttl + data = map[string]interface{}{ + "db_name": "plugin-test", + "creation_statements": testRole, + "default_ttl": "5m", + "max_ttl": "10m", + } + req = &logical.Request{ + Operation: logical.UpdateOperation, + Path: "roles/plugin-role-test", + Storage: config.StorageView, + Data: data, + } + resp, err = b.HandleRequest(context.Background(), req) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } + // Get creds + data = map[string]interface{}{} + req = &logical.Request{ + Operation: logical.ReadOperation, + Path: "creds/plugin-role-test", + Storage: config.StorageView, + Data: data, + } + credsResp, err = b.HandleRequest(context.Background(), req) + if err != nil || (credsResp != nil && credsResp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, credsResp) + } + // Test for #3812 + if credsResp.Secret.TTL != 5*time.Minute { + t.Fatalf("unexpected TTL of %d", credsResp.Secret.TTL) + } if !testCredsExist(t, credsResp, connURL) { t.Fatalf("Creds should exist") } diff --git a/builtin/logical/database/path_creds_create.go b/builtin/logical/database/path_creds_create.go index 16a56823ae47..bcc9d2377541 100644 --- a/builtin/logical/database/path_creds_create.go +++ b/builtin/logical/database/path_creds_create.go @@ -74,7 +74,12 @@ func (b *databaseBackend) pathCredsCreateRead() framework.OperationFunc { } } - expiration := time.Now().Add(role.DefaultTTL) + ttl := role.DefaultTTL + if ttl == 0 || (role.MaxTTL > 0 && ttl > role.MaxTTL) { + ttl = role.MaxTTL + } + + expiration := time.Now().Add(ttl) usernameConfig := dbplugin.UsernameConfig{ DisplayName: req.DisplayName, @@ -96,7 +101,7 @@ func (b *databaseBackend) pathCredsCreateRead() framework.OperationFunc { "username": username, "role": name, }) - resp.Secret.TTL = role.DefaultTTL + resp.Secret.TTL = ttl unlockFunc() return resp, nil diff --git a/builtin/logical/mongodb/path_creds_create.go b/builtin/logical/mongodb/path_creds_create.go index 535f5b831014..46a5f18966ae 100644 --- a/builtin/logical/mongodb/path_creds_create.go +++ b/builtin/logical/mongodb/path_creds_create.go @@ -95,7 +95,13 @@ func (b *backend) pathCredsCreateRead(ctx context.Context, req *logical.Request, "username": username, "db": role.DB, }) - resp.Secret.TTL = leaseConfig.TTL + + ttl := leaseConfig.TTL + if ttl == 0 || (leaseConfig.MaxTTL > 0 && ttl > leaseConfig.MaxTTL) { + ttl = leaseConfig.MaxTTL + } + resp.Secret.TTL = ttl + return resp, nil } diff --git a/builtin/logical/mssql/path_creds_create.go b/builtin/logical/mssql/path_creds_create.go index 8eb82d4b1f8b..df538bfced98 100644 --- a/builtin/logical/mssql/path_creds_create.go +++ b/builtin/logical/mssql/path_creds_create.go @@ -115,7 +115,13 @@ func (b *backend) pathCredsCreateRead(ctx context.Context, req *logical.Request, }, map[string]interface{}{ "username": username, }) - resp.Secret.TTL = leaseConfig.TTL + + ttl := leaseConfig.TTL + if ttl == 0 || (leaseConfig.TTLMax > 0 && ttl > leaseConfig.TTLMax) { + ttl = leaseConfig.TTLMax + } + resp.Secret.TTL = ttl + return resp, nil } diff --git a/builtin/logical/mysql/path_role_create.go b/builtin/logical/mysql/path_role_create.go index 48aaeba3d3a3..8a2607e34367 100644 --- a/builtin/logical/mysql/path_role_create.go +++ b/builtin/logical/mysql/path_role_create.go @@ -129,7 +129,13 @@ func (b *backend) pathRoleCreateRead(ctx context.Context, req *logical.Request, "username": username, "role": name, }) - resp.Secret.TTL = lease.Lease + + ttl := lease.Lease + if ttl == 0 || (lease.LeaseMax > 0 && ttl > lease.LeaseMax) { + ttl = lease.LeaseMax + } + resp.Secret.TTL = ttl + return resp, nil } diff --git a/builtin/logical/postgresql/path_role_create.go b/builtin/logical/postgresql/path_role_create.go index 18fe8709ad4a..5dc010ba9c9f 100644 --- a/builtin/logical/postgresql/path_role_create.go +++ b/builtin/logical/postgresql/path_role_create.go @@ -63,6 +63,11 @@ func (b *backend) pathRoleCreateRead(ctx context.Context, req *logical.Request, } } + ttl := lease.Lease + if ttl == 0 || (lease.LeaseMax > 0 && ttl > lease.LeaseMax) { + ttl = lease.LeaseMax + } + // Generate the username, password and expiration. PG limits user to 63 characters displayName := req.DisplayName if len(displayName) > 26 { @@ -81,7 +86,7 @@ func (b *backend) pathRoleCreateRead(ctx context.Context, req *logical.Request, return nil, err } expiration := time.Now(). - Add(lease.Lease). + Add(ttl). Format("2006-01-02 15:04:05-0700") // Get our handle @@ -142,7 +147,7 @@ func (b *backend) pathRoleCreateRead(ctx context.Context, req *logical.Request, "username": username, "role": name, }) - resp.Secret.TTL = lease.Lease + resp.Secret.TTL = ttl return resp, nil } diff --git a/builtin/logical/rabbitmq/path_role_create.go b/builtin/logical/rabbitmq/path_role_create.go index 789a8273b4e7..11b753e2e6ec 100644 --- a/builtin/logical/rabbitmq/path_role_create.go +++ b/builtin/logical/rabbitmq/path_role_create.go @@ -103,8 +103,13 @@ func (b *backend) pathCredsRead(ctx context.Context, req *logical.Request, d *fr if err != nil { return nil, err } + if lease != nil { - resp.Secret.TTL = lease.TTL + ttl := lease.TTL + if ttl == 0 || (lease.MaxTTL > 0 && ttl > lease.MaxTTL) { + ttl = lease.MaxTTL + } + resp.Secret.TTL = ttl } return resp, nil