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:
parent
efd0023d89
commit
62ba3f381f
|
@ -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.`)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue