From d34254ca3f518ba2f4d023813939b320bb8d8b89 Mon Sep 17 00:00:00 2001 From: vishalnayak Date: Sun, 15 Apr 2018 19:59:53 -0400 Subject: [PATCH 1/4] Add identity_policies to token lookup --- vault/token_store.go | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index db1dbbf60b23..fc1fe6591f95 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -18,6 +18,7 @@ import ( "github.com/hashicorp/go-multierror" "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/jsonutil" "github.com/hashicorp/vault/helper/locksutil" "github.com/hashicorp/vault/helper/parseutil" @@ -104,6 +105,8 @@ type TokenStore struct { salt *salt.Salt tidyLock int64 + + identityPoliciesDeriver func(string) (*identity.Entity, []string, error) } // NewTokenStore is used to construct a token store that is @@ -114,11 +117,12 @@ func NewTokenStore(ctx context.Context, logger log.Logger, c *Core, config *logi // Initialize the store t := &TokenStore{ - view: view, - cubbyholeDestroyer: destroyCubbyhole, - logger: logger, - tokenLocks: locksutil.CreateLocks(), - saltLock: sync.RWMutex{}, + view: view, + cubbyholeDestroyer: destroyCubbyhole, + logger: logger, + tokenLocks: locksutil.CreateLocks(), + saltLock: sync.RWMutex{}, + identityPoliciesDeriver: c.fetchEntityAndDerivedPolicies, } if c.policyStore != nil { @@ -2204,6 +2208,16 @@ func (ts *TokenStore) handleLookup(ctx context.Context, req *logical.Request, da resp.Data["issue_time"] = leaseTimes.IssueTime } + if out.EntityID != "" { + _, identityPolicies, err := ts.identityPoliciesDeriver(out.EntityID) + if err != nil { + return nil, err + } + if len(identityPolicies) != 0 { + resp.Data["identity_policies"] = identityPolicies + } + } + if urltoken { resp.AddWarning(`Using a token in the path is unsafe as the token can be logged in many places. Please use POST or PUT with the token passed in via the "token" parameter.`) } From cc98ea68537fef012ccf7026780281d7583c12f3 Mon Sep 17 00:00:00 2001 From: vishalnayak Date: Sun, 15 Apr 2018 20:36:11 -0400 Subject: [PATCH 2/4] add tests --- vault/token_store_ext_test.go | 210 ++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 vault/token_store_ext_test.go diff --git a/vault/token_store_ext_test.go b/vault/token_store_ext_test.go new file mode 100644 index 000000000000..98ccc256b117 --- /dev/null +++ b/vault/token_store_ext_test.go @@ -0,0 +1,210 @@ +package vault_test + +import ( + "fmt" + "reflect" + "sort" + "testing" + + "github.com/hashicorp/vault/api" + credLdap "github.com/hashicorp/vault/builtin/credential/ldap" + vaulthttp "github.com/hashicorp/vault/http" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/vault" +) + +func TestTokenStore_IdentityPolicies(t *testing.T) { + coreConfig := &vault.CoreConfig{ + CredentialBackends: map[string]logical.Factory{ + "ldap": credLdap.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 + + err := client.Sys().EnableAuthWithOptions("ldap", &api.EnableAuthOptions{ + Type: "ldap", + }) + if err != nil { + t.Fatal(err) + } + + _, err = client.Logical().Write("auth/ldap/config", map[string]interface{}{ + "url": "ldap://ldap.forumsys.com", + "userattr": "uid", + "userdn": "dc=example,dc=com", + "groupdn": "dc=example,dc=com", + "binddn": "cn=read-only-admin,dc=example,dc=com", + }) + if err != nil { + t.Fatal(err) + } + + _, err = client.Logical().Write("auth/ldap/groups/testgroup1", map[string]interface{}{ + "policies": "testgroup1-policy", + }) + if err != nil { + t.Fatal(err) + } + + _, err = client.Logical().Write("auth/ldap/users/tesla", map[string]interface{}{ + "policies": "default", + "groups": "testgroup1", + }) + if err != nil { + t.Fatal(err) + } + + // Login using LDAP + secret, err := client.Logical().Write("auth/ldap/login/tesla", map[string]interface{}{ + "password": "password", + }) + if err != nil { + t.Fatal(err) + } + ldapClientToken := secret.Auth.ClientToken + + secret, err = client.Logical().Read("auth/token/lookup/" + ldapClientToken) + if err != nil { + t.Fatal(err) + } + _, ok := secret.Data["identity_policies"] + if ok { + t.Fatalf("identity_policies should not have been set") + } + + entityID := secret.Data["entity_id"].(string) + + _, err = client.Logical().Write("identity/entity/id/"+entityID, map[string]interface{}{ + "policies": []string{ + "entity_policy_1", + "entity_policy_2", + }, + }) + if err != nil { + t.Fatal(err) + } + + secret, err = client.Logical().Read("auth/token/lookup/" + ldapClientToken) + if err != nil { + t.Fatal(err) + } + identityPolicies := secret.Data["identity_policies"].([]interface{}) + var actualPolicies []string + for _, item := range identityPolicies { + actualPolicies = append(actualPolicies, item.(string)) + } + sort.Strings(actualPolicies) + + expectedPolicies := []string{ + "entity_policy_1", + "entity_policy_2", + } + sort.Strings(expectedPolicies) + if !reflect.DeepEqual(expectedPolicies, actualPolicies) { + t.Fatalf("bad: identity policies; expected: %#v\nactual: %#v", expectedPolicies, actualPolicies) + } + + secret, err = client.Logical().Write("identity/group", map[string]interface{}{ + "policies": []string{ + "group_policy_1", + "group_policy_2", + }, + "member_entity_ids": []string{ + entityID, + }, + }) + if err != nil { + t.Fatal(err) + } + + secret, err = client.Logical().Read("auth/token/lookup/" + ldapClientToken) + if err != nil { + t.Fatal(err) + } + identityPolicies = secret.Data["identity_policies"].([]interface{}) + actualPolicies = nil + for _, item := range identityPolicies { + actualPolicies = append(actualPolicies, item.(string)) + } + sort.Strings(actualPolicies) + + expectedPolicies = []string{ + "entity_policy_1", + "entity_policy_2", + "group_policy_1", + "group_policy_2", + } + sort.Strings(expectedPolicies) + if !reflect.DeepEqual(expectedPolicies, actualPolicies) { + t.Fatalf("bad: identity policies; expected: %#v\nactual: %#v", expectedPolicies, actualPolicies) + } + + // Extract out the mount accessor for LDAP auth + auths, err := client.Sys().ListAuth() + if err != nil { + t.Fatal(err) + } + ldapMountAccessor1 := auths["ldap/"].Accessor + + // Create an external group + secret, err = client.Logical().Write("identity/group", map[string]interface{}{ + "type": "external", + "policies": []string{ + "external_group_policy_1", + "external_group_policy_2", + }, + }) + if err != nil { + t.Fatal(err) + } + ldapExtGroupID1 := secret.Data["id"].(string) + + // Associate a group from LDAP auth as a group-alias in the external group + _, err = client.Logical().Write("identity/group-alias", map[string]interface{}{ + "name": "testgroup1", + "mount_accessor": ldapMountAccessor1, + "canonical_id": ldapExtGroupID1, + }) + if err != nil { + t.Fatal(err) + } + + // Renew token to refresh external group memberships + secret, err = client.Auth().Token().Renew(ldapClientToken, 10) + if err != nil { + t.Fatal(err) + } + + secret, err = client.Logical().Read("auth/token/lookup/" + ldapClientToken) + if err != nil { + t.Fatal(err) + } + identityPolicies = secret.Data["identity_policies"].([]interface{}) + actualPolicies = nil + for _, item := range identityPolicies { + actualPolicies = append(actualPolicies, item.(string)) + } + sort.Strings(actualPolicies) + fmt.Printf("actualPolicies: %#v\n", actualPolicies) + + expectedPolicies = []string{ + "entity_policy_1", + "entity_policy_2", + "group_policy_1", + "group_policy_2", + "external_group_policy_1", + "external_group_policy_2", + } + sort.Strings(expectedPolicies) + if !reflect.DeepEqual(expectedPolicies, actualPolicies) { + t.Fatalf("bad: identity policies; expected: %#v\nactual: %#v", expectedPolicies, actualPolicies) + } +} From e12cf60a4589426a7e6ccbefc26f616e85cf30c5 Mon Sep 17 00:00:00 2001 From: vishalnayak Date: Sun, 15 Apr 2018 20:40:41 -0400 Subject: [PATCH 3/4] naming change --- vault/token_store.go | 16 ++++++++-------- vault/token_store_ext_test.go | 2 -- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index fc1fe6591f95..4760cf9c714b 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -106,7 +106,7 @@ type TokenStore struct { tidyLock int64 - identityPoliciesDeriver func(string) (*identity.Entity, []string, error) + identityPoliciesDeriverFunc func(string) (*identity.Entity, []string, error) } // NewTokenStore is used to construct a token store that is @@ -117,12 +117,12 @@ func NewTokenStore(ctx context.Context, logger log.Logger, c *Core, config *logi // Initialize the store t := &TokenStore{ - view: view, - cubbyholeDestroyer: destroyCubbyhole, - logger: logger, - tokenLocks: locksutil.CreateLocks(), - saltLock: sync.RWMutex{}, - identityPoliciesDeriver: c.fetchEntityAndDerivedPolicies, + view: view, + cubbyholeDestroyer: destroyCubbyhole, + logger: logger, + tokenLocks: locksutil.CreateLocks(), + saltLock: sync.RWMutex{}, + identityPoliciesDeriverFunc: c.fetchEntityAndDerivedPolicies, } if c.policyStore != nil { @@ -2209,7 +2209,7 @@ func (ts *TokenStore) handleLookup(ctx context.Context, req *logical.Request, da } if out.EntityID != "" { - _, identityPolicies, err := ts.identityPoliciesDeriver(out.EntityID) + _, identityPolicies, err := ts.identityPoliciesDeriverFunc(out.EntityID) if err != nil { return nil, err } diff --git a/vault/token_store_ext_test.go b/vault/token_store_ext_test.go index 98ccc256b117..a8bd68046402 100644 --- a/vault/token_store_ext_test.go +++ b/vault/token_store_ext_test.go @@ -1,7 +1,6 @@ package vault_test import ( - "fmt" "reflect" "sort" "testing" @@ -193,7 +192,6 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { actualPolicies = append(actualPolicies, item.(string)) } sort.Strings(actualPolicies) - fmt.Printf("actualPolicies: %#v\n", actualPolicies) expectedPolicies = []string{ "entity_policy_1", From 6f25bc6b660a24f18b4e9a92a97772aaabb9ca93 Mon Sep 17 00:00:00 2001 From: vishalnayak Date: Sun, 15 Apr 2018 20:46:18 -0400 Subject: [PATCH 4/4] add commenting in tests --- vault/token_store_ext_test.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/vault/token_store_ext_test.go b/vault/token_store_ext_test.go index a8bd68046402..3ebc1928e2eb 100644 --- a/vault/token_store_ext_test.go +++ b/vault/token_store_ext_test.go @@ -28,6 +28,7 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { vault.TestWaitActive(t, core) client := cluster.Cores[0].Client + // Enable LDAP auth err := client.Sys().EnableAuthWithOptions("ldap", &api.EnableAuthOptions{ Type: "ldap", }) @@ -35,6 +36,7 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { t.Fatal(err) } + // Configure LDAP auth _, err = client.Logical().Write("auth/ldap/config", map[string]interface{}{ "url": "ldap://ldap.forumsys.com", "userattr": "uid", @@ -46,6 +48,7 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { t.Fatal(err) } + // Create group in LDAP auth _, err = client.Logical().Write("auth/ldap/groups/testgroup1", map[string]interface{}{ "policies": "testgroup1-policy", }) @@ -53,6 +56,7 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { t.Fatal(err) } + // Create user in LDAP auth _, err = client.Logical().Write("auth/ldap/users/tesla", map[string]interface{}{ "policies": "default", "groups": "testgroup1", @@ -70,6 +74,7 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { } ldapClientToken := secret.Auth.ClientToken + // At this point there shouldn't be any identity policy on the token secret, err = client.Logical().Read("auth/token/lookup/" + ldapClientToken) if err != nil { t.Fatal(err) @@ -79,8 +84,8 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { t.Fatalf("identity_policies should not have been set") } + // Extract the entity ID of the token and set some policies on the entity entityID := secret.Data["entity_id"].(string) - _, err = client.Logical().Write("identity/entity/id/"+entityID, map[string]interface{}{ "policies": []string{ "entity_policy_1", @@ -91,6 +96,7 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { t.Fatal(err) } + // Lookup the token and expect entity policies on the token secret, err = client.Logical().Read("auth/token/lookup/" + ldapClientToken) if err != nil { t.Fatal(err) @@ -111,6 +117,7 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { t.Fatalf("bad: identity policies; expected: %#v\nactual: %#v", expectedPolicies, actualPolicies) } + // Create identity group and add entity as its member secret, err = client.Logical().Write("identity/group", map[string]interface{}{ "policies": []string{ "group_policy_1", @@ -124,6 +131,7 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { t.Fatal(err) } + // Lookup token and expect both entity and group policies on the token secret, err = client.Logical().Read("auth/token/lookup/" + ldapClientToken) if err != nil { t.Fatal(err) @@ -146,7 +154,8 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { t.Fatalf("bad: identity policies; expected: %#v\nactual: %#v", expectedPolicies, actualPolicies) } - // Extract out the mount accessor for LDAP auth + // Create an external group and renew the token. This should add external + // group policies to the token. auths, err := client.Sys().ListAuth() if err != nil { t.Fatal(err) @@ -182,6 +191,8 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { t.Fatal(err) } + // Lookup token and expect entity, group and external group policies on the + // token secret, err = client.Logical().Read("auth/token/lookup/" + ldapClientToken) if err != nil { t.Fatal(err)