package approle import ( "context" "reflect" "strings" "testing" "time" "github.com/hashicorp/vault/helper/policyutil" "github.com/hashicorp/vault/logical" "github.com/mitchellh/mapstructure" ) func TestApprole_RoleNameLowerCasing(t *testing.T) { var resp *logical.Response var err error var roleID, secretID string b, storage := createBackendWithStorage(t) // Save a role with out LowerCaseRoleName set role := &roleStorageEntry{ RoleID: "testroleid", HMACKey: "testhmackey", Policies: []string{"default"}, BindSecretID: true, } err = b.setRoleEntry(context.Background(), storage, "testRoleName", role, "") if err != nil { t.Fatal(err) } secretIDReq := &logical.Request{ Path: "role/testRoleName/secret-id", Operation: logical.UpdateOperation, Storage: storage, } resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) } secretID = resp.Data["secret_id"].(string) roleID = "testroleid" // Regular login flow. This should succeed. resp, err = b.HandleRequest(context.Background(), &logical.Request{ Path: "login", Operation: logical.UpdateOperation, Storage: storage, Data: map[string]interface{}{ "role_id": roleID, "secret_id": secretID, }, }) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) } // Lower case the role name when generating the secret id secretIDReq.Path = "role/testrolename/secret-id" resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) } secretID = resp.Data["secret_id"].(string) // Login should fail resp, err = b.HandleRequest(context.Background(), &logical.Request{ Path: "login", Operation: logical.UpdateOperation, Storage: storage, Data: map[string]interface{}{ "role_id": roleID, "secret_id": secretID, }, }) if err != nil { t.Fatal(err) } if resp == nil || !resp.IsError() { t.Fatalf("expected an error") } // Delete the role and create it again. This time don't directly persist // it, but route the request to the creation handler so that it sets the // LowerCaseRoleName to true. resp, err = b.HandleRequest(context.Background(), &logical.Request{ Path: "role/testRoleName", Operation: logical.DeleteOperation, Storage: storage, }) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) } roleReq := &logical.Request{ Path: "role/testRoleName", Operation: logical.CreateOperation, Storage: storage, Data: map[string]interface{}{ "bind_secret_id": true, }, } resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) } // Create secret id with lower cased role name resp, err = b.HandleRequest(context.Background(), &logical.Request{ Path: "role/testrolename/secret-id", Operation: logical.UpdateOperation, Storage: storage, }) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) } secretID = resp.Data["secret_id"].(string) resp, err = b.HandleRequest(context.Background(), &logical.Request{ Path: "role/testrolename/role-id", Operation: logical.ReadOperation, Storage: storage, }) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) } roleID = resp.Data["role_id"].(string) // Login should pass resp, err = b.HandleRequest(context.Background(), &logical.Request{ Path: "login", Operation: logical.UpdateOperation, Storage: storage, Data: map[string]interface{}{ "role_id": roleID, "secret_id": secretID, }, }) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\nerr:%v", resp, err) } // Lookup of secret ID should work in case-insensitive manner resp, err = b.HandleRequest(context.Background(), &logical.Request{ Path: "role/testrolename/secret-id/lookup", Operation: logical.UpdateOperation, Storage: storage, Data: map[string]interface{}{ "secret_id": secretID, }, }) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) } if resp == nil { t.Fatalf("failed to lookup secret IDs") } // Listing of secret IDs should work in case-insensitive manner resp, err = b.HandleRequest(context.Background(), &logical.Request{ Path: "role/testrolename/secret-id", Operation: logical.ListOperation, Storage: storage, }) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) } if len(resp.Data["keys"].([]string)) != 1 { t.Fatalf("failed to list secret IDs") } } func TestAppRole_RoleReadSetIndex(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) roleReq := &logical.Request{ Path: "role/testrole", Operation: logical.CreateOperation, Storage: storage, Data: map[string]interface{}{ "bind_secret_id": true, }, } // Create a role resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\n err: %v\n", resp, err) } roleIDReq := &logical.Request{ Path: "role/testrole/role-id", Operation: logical.ReadOperation, Storage: storage, } // Get the role ID resp, err = b.HandleRequest(context.Background(), roleIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\n err: %v\n", resp, err) } roleID := resp.Data["role_id"].(string) // Delete the role ID index err = b.roleIDEntryDelete(context.Background(), storage, roleID) if err != nil { t.Fatal(err) } // Read the role again. This should add the index and return a warning roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\n err: %v\n", resp, err) } // Check if the warning is being returned if !strings.Contains(resp.Warnings[0], "Role identifier was missing an index back to role name.") { t.Fatalf("bad: expected a warning in the response") } roleIDIndex, err := b.roleIDEntry(context.Background(), storage, roleID) if err != nil { t.Fatal(err) } // Check if the index has been successfully created if roleIDIndex == nil || roleIDIndex.Name != "testrole" { t.Fatalf("bad: expected role to have an index") } roleReq.Operation = logical.UpdateOperation roleReq.Data = map[string]interface{}{ "bind_secret_id": true, "policies": "default", } // Check if updating and reading of roles work and that there are no lock // contentions dangling due to previous operation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\n err: %v\n", resp, err) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("bad: resp: %#v\n err: %v\n", resp, err) } } func TestAppRole_CIDRSubset(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) roleData := map[string]interface{}{ "role_id": "role-id-123", "policies": "a,b", "bound_cidr_list": "127.0.0.1/24", } roleReq := &logical.Request{ Operation: logical.CreateOperation, Path: "role/testrole1", Storage: storage, Data: roleData, } resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err: %v resp: %#v", err, resp) } secretIDData := map[string]interface{}{ "cidr_list": "127.0.0.1/16", } secretIDReq := &logical.Request{ Operation: logical.UpdateOperation, Storage: storage, Path: "role/testrole1/secret-id", Data: secretIDData, } resp, err = b.HandleRequest(context.Background(), secretIDReq) if resp != nil || resp.IsError() { t.Fatalf("resp:%#v", resp) } if err == nil { t.Fatal("expected an error") } roleData["bound_cidr_list"] = "192.168.27.29/16,172.245.30.40/24,10.20.30.40/30" roleReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err: %v resp: %#v", err, resp) } secretIDData["cidr_list"] = "192.168.27.29/20,172.245.30.40/25,10.20.30.40/32" resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil { t.Fatal(err) } if resp != nil && resp.IsError() { t.Fatalf("resp: %#v", resp) } } func TestAppRole_RoleConstraints(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) roleData := map[string]interface{}{ "role_id": "role-id-123", "policies": "a,b", } roleReq := &logical.Request{ Operation: logical.CreateOperation, Path: "role/testrole1", Storage: storage, Data: roleData, } // Set bind_secret_id, which is enabled by default resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } // Set bound_cidr_list alone by explicitly disabling bind_secret_id roleReq.Operation = logical.UpdateOperation roleData["bind_secret_id"] = false roleData["bound_cidr_list"] = "0.0.0.0/0" resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } // Remove both constraints roleReq.Operation = logical.UpdateOperation roleData["bound_cidr_list"] = "" roleData["bind_secret_id"] = false resp, err = b.HandleRequest(context.Background(), roleReq) if resp != nil && resp.IsError() { t.Fatalf("err:%v, resp:%#v", err, resp) } if err == nil { t.Fatalf("expected an error") } } func TestAppRole_RoleIDUpdate(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) roleData := map[string]interface{}{ "role_id": "role-id-123", "policies": "a,b", "secret_id_num_uses": 10, "secret_id_ttl": 300, "token_ttl": 400, "token_max_ttl": 500, } roleReq := &logical.Request{ Operation: logical.CreateOperation, Path: "role/testrole1", Storage: storage, Data: roleData, } resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleIDUpdateReq := &logical.Request{ Operation: logical.UpdateOperation, Path: "role/testrole1/role-id", Storage: storage, Data: map[string]interface{}{ "role_id": "customroleid", }, } resp, err = b.HandleRequest(context.Background(), roleIDUpdateReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } secretIDReq := &logical.Request{ Operation: logical.UpdateOperation, Storage: storage, Path: "role/testrole1/secret-id", } resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } secretID := resp.Data["secret_id"].(string) loginData := map[string]interface{}{ "role_id": "customroleid", "secret_id": secretID, } loginReq := &logical.Request{ Operation: logical.UpdateOperation, Path: "login", Storage: storage, Data: loginData, Connection: &logical.Connection{ RemoteAddr: "127.0.0.1", }, } resp, err = b.HandleRequest(context.Background(), loginReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Auth == nil { t.Fatalf("expected a non-nil auth object in the response") } } func TestAppRole_RoleIDUniqueness(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) roleData := map[string]interface{}{ "role_id": "role-id-123", "policies": "a,b", "secret_id_num_uses": 10, "secret_id_ttl": 300, "token_ttl": 400, "token_max_ttl": 500, } roleReq := &logical.Request{ Operation: logical.CreateOperation, Path: "role/testrole1", Storage: storage, Data: roleData, } resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Path = "role/testrole2" resp, err = b.HandleRequest(context.Background(), roleReq) if err == nil && !(resp != nil && resp.IsError()) { t.Fatalf("expected an error: got resp:%#v", resp) } roleData["role_id"] = "role-id-456" resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.UpdateOperation roleData["role_id"] = "role-id-123" resp, err = b.HandleRequest(context.Background(), roleReq) if err == nil && !(resp != nil && resp.IsError()) { t.Fatalf("expected an error: got resp:%#v", resp) } roleReq.Path = "role/testrole1" roleData["role_id"] = "role-id-456" resp, err = b.HandleRequest(context.Background(), roleReq) if err == nil && !(resp != nil && resp.IsError()) { t.Fatalf("expected an error: got resp:%#v", resp) } roleIDData := map[string]interface{}{ "role_id": "role-id-456", } roleIDReq := &logical.Request{ Operation: logical.UpdateOperation, Path: "role/testrole1/role-id", Storage: storage, Data: roleIDData, } resp, err = b.HandleRequest(context.Background(), roleIDReq) if err == nil && !(resp != nil && resp.IsError()) { t.Fatalf("expected an error: got resp:%#v", resp) } roleIDData["role_id"] = "role-id-123" roleIDReq.Path = "role/testrole2/role-id" resp, err = b.HandleRequest(context.Background(), roleIDReq) if err == nil && !(resp != nil && resp.IsError()) { t.Fatalf("expected an error: got resp:%#v", resp) } roleIDData["role_id"] = "role-id-2000" resp, err = b.HandleRequest(context.Background(), roleIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleIDData["role_id"] = "role-id-1000" roleIDReq.Path = "role/testrole1/role-id" resp, err = b.HandleRequest(context.Background(), roleIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } } func TestAppRole_RoleDeleteSecretID(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) createRole(t, b, storage, "role1", "a,b") secretIDReq := &logical.Request{ Operation: logical.UpdateOperation, Storage: storage, Path: "role/role1/secret-id", } // Create 3 secrets on the role resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } listReq := &logical.Request{ Operation: logical.ListOperation, Storage: storage, Path: "role/role1/secret-id", } resp, err = b.HandleRequest(context.Background(), listReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } secretIDAccessors := resp.Data["keys"].([]string) if len(secretIDAccessors) != 3 { t.Fatalf("bad: len of secretIDAccessors: expected:3 actual:%d", len(secretIDAccessors)) } roleReq := &logical.Request{ Operation: logical.DeleteOperation, Storage: storage, Path: "role/role1", } resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } resp, err = b.HandleRequest(context.Background(), listReq) if err != nil || resp == nil || (resp != nil && !resp.IsError()) { t.Fatalf("expected an error. err:%v resp:%#v", err, resp) } } func TestAppRole_RoleSecretIDReadDelete(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) createRole(t, b, storage, "role1", "a,b") secretIDCreateReq := &logical.Request{ Operation: logical.UpdateOperation, Storage: storage, Path: "role/role1/secret-id", } resp, err = b.HandleRequest(context.Background(), secretIDCreateReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } secretID := resp.Data["secret_id"].(string) if secretID == "" { t.Fatal("expected non empty secret ID") } secretIDReq := &logical.Request{ Operation: logical.UpdateOperation, Storage: storage, Path: "role/role1/secret-id/lookup", Data: map[string]interface{}{ "secret_id": secretID, }, } resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data == nil { t.Fatal(err) } deleteSecretIDReq := &logical.Request{ Operation: logical.DeleteOperation, Storage: storage, Path: "role/role1/secret-id/destroy", Data: map[string]interface{}{ "secret_id": secretID, }, } resp, err = b.HandleRequest(context.Background(), deleteSecretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } resp, err = b.HandleRequest(context.Background(), secretIDReq) if resp != nil && resp.IsError() { t.Fatalf("error response:%#v", resp) } if err != nil { t.Fatal(err) } } func TestAppRole_RoleSecretIDAccessorReadDelete(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) createRole(t, b, storage, "role1", "a,b") secretIDReq := &logical.Request{ Operation: logical.UpdateOperation, Storage: storage, Path: "role/role1/secret-id", } resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } listReq := &logical.Request{ Operation: logical.ListOperation, Storage: storage, Path: "role/role1/secret-id", } resp, err = b.HandleRequest(context.Background(), listReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } hmacSecretID := resp.Data["keys"].([]string)[0] hmacReq := &logical.Request{ Operation: logical.UpdateOperation, Storage: storage, Path: "role/role1/secret-id-accessor/lookup", Data: map[string]interface{}{ "secret_id_accessor": hmacSecretID, }, } resp, err = b.HandleRequest(context.Background(), hmacReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data == nil { t.Fatal(err) } hmacReq.Path = "role/role1/secret-id-accessor/destroy" resp, err = b.HandleRequest(context.Background(), hmacReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } hmacReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), hmacReq) if resp != nil && resp.IsError() { t.Fatalf("err:%v resp:%#v", err, resp) } if err == nil { t.Fatalf("expected an error") } } func TestAppRoleRoleListSecretID(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) createRole(t, b, storage, "role1", "a,b") secretIDReq := &logical.Request{ Operation: logical.UpdateOperation, Storage: storage, Path: "role/role1/secret-id", } // Create 5 'secret_id's resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } resp, err = b.HandleRequest(context.Background(), secretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } listReq := &logical.Request{ Operation: logical.ListOperation, Storage: storage, Path: "role/role1/secret-id/", } resp, err = b.HandleRequest(context.Background(), listReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } secrets := resp.Data["keys"].([]string) if len(secrets) != 5 { t.Fatalf("bad: len of secrets: expected:5 actual:%d", len(secrets)) } } func TestAppRole_RoleList(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) createRole(t, b, storage, "role1", "a,b") createRole(t, b, storage, "role2", "c,d") createRole(t, b, storage, "role3", "e,f") createRole(t, b, storage, "role4", "g,h") createRole(t, b, storage, "role5", "i,j") listReq := &logical.Request{ Operation: logical.ListOperation, Path: "role", Storage: storage, } resp, err = b.HandleRequest(context.Background(), listReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } actual := resp.Data["keys"].([]string) expected := []string{"role1", "role2", "role3", "role4", "role5"} if !policyutil.EquivalentPolicies(actual, expected) { t.Fatalf("bad: listed roles: expected:%s\nactual:%s", expected, actual) } } func TestAppRole_RoleSecretID(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) roleData := map[string]interface{}{ "policies": "p,q,r,s", "secret_id_num_uses": 10, "secret_id_ttl": 300, "token_ttl": 400, "token_max_ttl": 500, } roleReq := &logical.Request{ Operation: logical.CreateOperation, Path: "role/role1", Storage: storage, Data: roleData, } resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleSecretIDReq := &logical.Request{ Operation: logical.UpdateOperation, Path: "role/role1/secret-id", Storage: storage, } resp, err = b.HandleRequest(context.Background(), roleSecretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["secret_id"].(string) == "" { t.Fatalf("failed to generate secret_id") } roleSecretIDReq.Path = "role/role1/custom-secret-id" roleCustomSecretIDData := map[string]interface{}{ "secret_id": "abcd123", } roleSecretIDReq.Data = roleCustomSecretIDData roleSecretIDReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleSecretIDReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["secret_id"] != "abcd123" { t.Fatalf("failed to set specific secret_id to role") } } func TestAppRole_RoleCRUD(t *testing.T) { var resp *logical.Response var err error b, storage := createBackendWithStorage(t) roleData := map[string]interface{}{ "policies": "p,q,r,s", "secret_id_num_uses": 10, "secret_id_ttl": 300, "token_ttl": 400, "token_max_ttl": 500, "token_num_uses": 600, "bound_cidr_list": "127.0.0.1/32,127.0.0.1/16", } roleReq := &logical.Request{ Operation: logical.CreateOperation, Path: "role/role1", Storage: storage, Data: roleData, } resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } expected := map[string]interface{}{ "bind_secret_id": true, "policies": []string{"p", "q", "r", "s"}, "secret_id_num_uses": 10, "secret_id_ttl": 300, "token_ttl": 400, "token_max_ttl": 500, "token_num_uses": 600, "bound_cidr_list": "127.0.0.1/32,127.0.0.1/16", } var expectedStruct roleStorageEntry err = mapstructure.Decode(expected, &expectedStruct) if err != nil { t.Fatal(err) } var actualStruct roleStorageEntry err = mapstructure.Decode(resp.Data, &actualStruct) if err != nil { t.Fatal(err) } expectedStruct.RoleID = actualStruct.RoleID if !reflect.DeepEqual(expectedStruct, actualStruct) { t.Fatalf("bad:\nexpected:%#v\nactual:%#v\n", expectedStruct, actualStruct) } roleData = map[string]interface{}{ "role_id": "test_role_id", "policies": "a,b,c,d", "secret_id_num_uses": 100, "secret_id_ttl": 3000, "token_ttl": 4000, "token_max_ttl": 5000, } roleReq.Data = roleData roleReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } expected = map[string]interface{}{ "policies": []string{"a", "b", "c", "d"}, "secret_id_num_uses": 100, "secret_id_ttl": 3000, "token_ttl": 4000, "token_max_ttl": 5000, } err = mapstructure.Decode(expected, &expectedStruct) if err != nil { t.Fatal(err) } err = mapstructure.Decode(resp.Data, &actualStruct) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(expectedStruct, actualStruct) { t.Fatalf("bad:\nexpected:%#v\nactual:%#v\n", expectedStruct, actualStruct) } // RU for role_id field roleReq.Path = "role/role1/role-id" roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["role_id"].(string) != "test_role_id" { t.Fatalf("bad: role_id: expected:test_role_id actual:%s\n", resp.Data["role_id"].(string)) } roleReq.Data = map[string]interface{}{"role_id": "custom_role_id"} roleReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["role_id"].(string) != "custom_role_id" { t.Fatalf("bad: role_id: expected:custom_role_id actual:%s\n", resp.Data["role_id"].(string)) } // RUD for bind_secret_id field roleReq.Path = "role/role1/bind-secret-id" roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Data = map[string]interface{}{"bind_secret_id": false} roleReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["bind_secret_id"].(bool) { t.Fatalf("bad: bind_secret_id: expected:false actual:%t\n", resp.Data["bind_secret_id"].(bool)) } roleReq.Operation = logical.DeleteOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if !resp.Data["bind_secret_id"].(bool) { t.Fatalf("expected the default value of 'true' to be set") } // RUD for policies field roleReq.Path = "role/role1/policies" roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Data = map[string]interface{}{"policies": "a1,b1,c1,d1"} roleReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if !reflect.DeepEqual(resp.Data["policies"].([]string), []string{"a1", "b1", "c1", "d1"}) { t.Fatalf("bad: policies: actual:%s\n", resp.Data["policies"].([]string)) } roleReq.Operation = logical.DeleteOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } expectedPolicies := []string{"default"} actualPolicies := resp.Data["policies"].([]string) if !policyutil.EquivalentPolicies(expectedPolicies, actualPolicies) { t.Fatalf("bad: policies: expected:%s actual:%s", expectedPolicies, actualPolicies) } // RUD for secret-id-num-uses field roleReq.Path = "role/role1/secret-id-num-uses" roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Data = map[string]interface{}{"secret_id_num_uses": 200} roleReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["secret_id_num_uses"].(int) != 200 { t.Fatalf("bad: secret_id_num_uses: expected:200 actual:%d\n", resp.Data["secret_id_num_uses"].(int)) } roleReq.Operation = logical.DeleteOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["secret_id_num_uses"].(int) != 0 { t.Fatalf("expected value to be reset") } // RUD for secret_id_ttl field roleReq.Path = "role/role1/secret-id-ttl" roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Data = map[string]interface{}{"secret_id_ttl": 3001} roleReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["secret_id_ttl"].(time.Duration) != 3001 { t.Fatalf("bad: secret_id_ttl: expected:3001 actual:%d\n", resp.Data["secret_id_ttl"].(time.Duration)) } roleReq.Operation = logical.DeleteOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["secret_id_ttl"].(time.Duration) != 0 { t.Fatalf("expected value to be reset") } // RUD for secret-id-num-uses field roleReq.Path = "role/role1/token-num-uses" roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["token_num_uses"].(int) != 600 { t.Fatalf("bad: token_num_uses: expected:600 actual:%d\n", resp.Data["token_num_uses"].(int)) } roleReq.Data = map[string]interface{}{"token_num_uses": 60} roleReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["token_num_uses"].(int) != 60 { t.Fatalf("bad: token_num_uses: expected:60 actual:%d\n", resp.Data["token_num_uses"].(int)) } roleReq.Operation = logical.DeleteOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["token_num_uses"].(int) != 0 { t.Fatalf("expected value to be reset") } // RUD for 'period' field roleReq.Path = "role/role1/period" roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Data = map[string]interface{}{"period": 9001} roleReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["period"].(time.Duration) != 9001 { t.Fatalf("bad: period: expected:9001 actual:%d\n", resp.Data["9001"].(time.Duration)) } roleReq.Operation = logical.DeleteOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["period"].(time.Duration) != 0 { t.Fatalf("expected value to be reset") } // RUD for token_ttl field roleReq.Path = "role/role1/token-ttl" roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Data = map[string]interface{}{"token_ttl": 4001} roleReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["token_ttl"].(time.Duration) != 4001 { t.Fatalf("bad: token_ttl: expected:4001 actual:%d\n", resp.Data["token_ttl"].(time.Duration)) } roleReq.Operation = logical.DeleteOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["token_ttl"].(time.Duration) != 0 { t.Fatalf("expected value to be reset") } // RUD for token_max_ttl field roleReq.Path = "role/role1/token-max-ttl" roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Data = map[string]interface{}{"token_max_ttl": 5001} roleReq.Operation = logical.UpdateOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["token_max_ttl"].(time.Duration) != 5001 { t.Fatalf("bad: token_max_ttl: expected:5001 actual:%d\n", resp.Data["token_max_ttl"].(time.Duration)) } roleReq.Operation = logical.DeleteOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp.Data["token_max_ttl"].(time.Duration) != 0 { t.Fatalf("expected value to be reset") } // Delete test for role roleReq.Path = "role/role1" roleReq.Operation = logical.DeleteOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } roleReq.Operation = logical.ReadOperation resp, err = b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } if resp != nil { t.Fatalf("expected a nil response") } } func createRole(t *testing.T, b *backend, s logical.Storage, roleName, policies string) { roleData := map[string]interface{}{ "policies": policies, "secret_id_num_uses": 10, "secret_id_ttl": 300, "token_ttl": 400, "token_max_ttl": 500, } roleReq := &logical.Request{ Operation: logical.CreateOperation, Path: "role/" + roleName, Storage: s, Data: roleData, } resp, err := b.HandleRequest(context.Background(), roleReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%v resp:%#v", err, resp) } }