Identity policies in token lookup (#4366)

* Add identity_policies to token lookup

* add tests

* naming change

* add commenting in tests
This commit is contained in:
Vishal Nayak 2018-04-17 11:16:26 -04:00 committed by GitHub
parent efd0023d89
commit 62ba3f381f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 238 additions and 5 deletions

View File

@ -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
identityPoliciesDeriverFunc 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{},
identityPoliciesDeriverFunc: 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.identityPoliciesDeriverFunc(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.`)
}

View File

@ -0,0 +1,219 @@
package vault_test
import (
"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
// Enable LDAP auth
err := client.Sys().EnableAuthWithOptions("ldap", &api.EnableAuthOptions{
Type: "ldap",
})
if err != nil {
t.Fatal(err)
}
// Configure LDAP auth
_, 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)
}
// Create group in LDAP auth
_, err = client.Logical().Write("auth/ldap/groups/testgroup1", map[string]interface{}{
"policies": "testgroup1-policy",
})
if err != nil {
t.Fatal(err)
}
// Create user in LDAP auth
_, 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
// 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)
}
_, ok := secret.Data["identity_policies"]
if ok {
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",
"entity_policy_2",
},
})
if err != nil {
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)
}
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)
}
// Create identity group and add entity as its member
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)
}
// 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)
}
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)
}
// 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)
}
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)
}
// 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)
}
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",
"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)
}
}