// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package vault_test import ( "encoding/json" "testing" "time" "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/builtin/credential/approle" vaulthttp "github.com/hashicorp/vault/http" "github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/vault" ) func TestExpiration_RenewToken_TestCluster(t *testing.T) { // Use a TestCluster and the approle backend to test renewal coreConfig := &vault.CoreConfig{ CredentialBackends: map[string]logical.Factory{ "approle": approle.Factory, }, } cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{ HandlerFunc: vaulthttp.Handler, }) cluster.Start() defer cluster.Cleanup() core := cluster.Cores[0].Core vault.TestWaitActive(t, core) client := cluster.Cores[0].Client // Mount the auth backend err := client.Sys().EnableAuthWithOptions("approle", &api.EnableAuthOptions{ Type: "approle", }) if err != nil { t.Fatal(err) } // Tune the mount err = client.Sys().TuneMount("auth/approle", api.MountConfigInput{ DefaultLeaseTTL: "5s", MaxLeaseTTL: "5s", }) if err != nil { t.Fatal(err) } // Create role resp, err := client.Logical().Write("auth/approle/role/role-period", map[string]interface{}{ "period": "5s", }) if err != nil { t.Fatal(err) } // Get role_id resp, err = client.Logical().Read("auth/approle/role/role-period/role-id") if err != nil { t.Fatal(err) } if resp == nil { t.Fatal("expected a response for fetching the role-id") } roleID := resp.Data["role_id"] // Get secret_id resp, err = client.Logical().Write("auth/approle/role/role-period/secret-id", map[string]interface{}{}) if err != nil { t.Fatal(err) } if resp == nil { t.Fatal("expected a response for fetching the secret-id") } secretID := resp.Data["secret_id"] // Login resp, err = client.Logical().Write("auth/approle/login", map[string]interface{}{ "role_id": roleID, "secret_id": secretID, }) if err != nil { t.Fatal(err) } if resp == nil { t.Fatal("expected a response for login") } if resp.Auth == nil { t.Fatal("expected auth object from response") } if resp.Auth.ClientToken == "" { t.Fatal("expected a client token") } roleToken := resp.Auth.ClientToken // Wait 3 seconds time.Sleep(3 * time.Second) // Renew resp, err = client.Logical().Write("auth/token/renew", map[string]interface{}{ "token": roleToken, }) if err != nil { t.Fatal(err) } if resp == nil { t.Fatal("expected a response for renew") } // Perform token lookup and verify TTL resp, err = client.Auth().Token().Lookup(roleToken) if err != nil { t.Fatal(err) } if resp == nil { t.Fatal("expected a response for token lookup") } ttlRaw, ok := resp.Data["ttl"].(json.Number) if !ok { t.Fatal("no ttl value found in data object") } ttlInt, err := ttlRaw.Int64() if err != nil { t.Fatalf("unable to convert ttl to int: %s", err) } ttl := time.Duration(ttlInt) * time.Second if ttl < 4*time.Second { t.Fatal("expected ttl value to be around 5s") } // Wait 3 seconds time.Sleep(3 * time.Second) // Do a second renewal to ensure that period can be renewed past sys/mount max_ttl resp, err = client.Logical().Write("auth/token/renew", map[string]interface{}{ "token": roleToken, }) if err != nil { t.Fatal(err) } if resp == nil { t.Fatal("expected a response for renew") } // Perform token lookup and verify TTL resp, err = client.Auth().Token().Lookup(roleToken) if err != nil { t.Fatal(err) } if resp == nil { t.Fatal("expected a response for token lookup") } ttlRaw, ok = resp.Data["ttl"].(json.Number) if !ok { t.Fatal("no ttl value found in data object") } ttlInt, err = ttlRaw.Int64() if err != nil { t.Fatalf("unable to convert ttl to int: %s", err) } ttl = time.Duration(ttlInt) * time.Second if ttl < 4*time.Second { t.Fatal("expected ttl value to be around 5s") } }