7bae606662
* external identity groups * add local LDAP groups as well to group aliases * add group aliases for okta credential backend * Fix panic in tests * fix build failure * remove duplicated struct tag * add test steps to test out removal of group member during renewals * Add comment for having a prefix check in router * fix tests * s/parent_id/canonical_id * s/parent/canonical in comments and errors
369 lines
8.7 KiB
Go
369 lines
8.7 KiB
Go
package command
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/hashicorp/vault/api"
|
|
"github.com/hashicorp/vault/builtin/credential/ldap"
|
|
vaulthttp "github.com/hashicorp/vault/http"
|
|
"github.com/hashicorp/vault/logical"
|
|
"github.com/hashicorp/vault/vault"
|
|
logxi "github.com/mgutz/logxi/v1"
|
|
)
|
|
|
|
func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
|
|
var err error
|
|
coreConfig := &vault.CoreConfig{
|
|
DisableMlock: true,
|
|
DisableCache: true,
|
|
Logger: logxi.NullLog,
|
|
CredentialBackends: map[string]logical.Factory{
|
|
"ldap": ldap.Factory,
|
|
},
|
|
}
|
|
|
|
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
|
|
HandlerFunc: vaulthttp.Handler,
|
|
})
|
|
|
|
cluster.Start()
|
|
defer cluster.Cleanup()
|
|
|
|
cores := cluster.Cores
|
|
|
|
vault.TestWaitActive(t, cores[0].Core)
|
|
|
|
client := cores[0].Client
|
|
|
|
err = client.Sys().EnableAuthWithOptions("ldap", &api.EnableAuthOptions{
|
|
Type: "ldap",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
auth, err := client.Sys().ListAuth()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
accessor := auth["ldap/"].Accessor
|
|
|
|
secret, err := client.Logical().Write("identity/group", map[string]interface{}{
|
|
"type": "external",
|
|
"name": "ldap_Italians",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
italiansGroupID := secret.Data["id"].(string)
|
|
|
|
secret, err = client.Logical().Write("identity/group", map[string]interface{}{
|
|
"type": "external",
|
|
"name": "ldap_Scientists",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
scientistsGroupID := secret.Data["id"].(string)
|
|
|
|
secret, err = client.Logical().Write("identity/group", map[string]interface{}{
|
|
"type": "external",
|
|
"name": "ldap_devops",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
devopsGroupID := secret.Data["id"].(string)
|
|
|
|
secret, err = client.Logical().Write("identity/group-alias", map[string]interface{}{
|
|
"name": "Italians",
|
|
"canonical_id": italiansGroupID,
|
|
"mount_accessor": accessor,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
secret, err = client.Logical().Write("identity/group-alias", map[string]interface{}{
|
|
"name": "Scientists",
|
|
"canonical_id": scientistsGroupID,
|
|
"mount_accessor": accessor,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
secret, err = client.Logical().Write("identity/group-alias", map[string]interface{}{
|
|
"name": "devops",
|
|
"canonical_id": devopsGroupID,
|
|
"mount_accessor": accessor,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
secret, err = client.Logical().Read("identity/group/id/" + italiansGroupID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
aliasMap := secret.Data["alias"].(map[string]interface{})
|
|
if aliasMap["canonical_id"] != italiansGroupID ||
|
|
aliasMap["name"] != "Italians" ||
|
|
aliasMap["mount_accessor"] != accessor {
|
|
t.Fatalf("bad: group alias: %#v\n", aliasMap)
|
|
}
|
|
|
|
secret, err = client.Logical().Read("identity/group/id/" + scientistsGroupID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
aliasMap = secret.Data["alias"].(map[string]interface{})
|
|
if aliasMap["canonical_id"] != scientistsGroupID ||
|
|
aliasMap["name"] != "Scientists" ||
|
|
aliasMap["mount_accessor"] != accessor {
|
|
t.Fatalf("bad: group alias: %#v\n", aliasMap)
|
|
}
|
|
|
|
// Configure LDAP auth backend
|
|
secret, 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 a local group in LDAP backend
|
|
secret, err = client.Logical().Write("auth/ldap/groups/devops", map[string]interface{}{
|
|
"policies": "default",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Create a local group in LDAP backend
|
|
secret, err = client.Logical().Write("auth/ldap/groups/engineers", map[string]interface{}{
|
|
"policies": "default",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Create a local user in LDAP
|
|
secret, err = client.Logical().Write("auth/ldap/users/tesla", map[string]interface{}{
|
|
"policies": "default",
|
|
"groups": "engineers,devops",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Login with LDAP and create a token
|
|
secret, err = client.Logical().Write("auth/ldap/login/tesla", map[string]interface{}{
|
|
"password": "password",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
token := secret.Auth.ClientToken
|
|
|
|
// Lookup the token to get the entity ID
|
|
secret, err = client.Auth().Token().Lookup(token)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
entityID := secret.Data["entity_id"].(string)
|
|
|
|
// Re-read the Scientists, Italians and devops group. This entity ID should have
|
|
// been added to both of these groups by now.
|
|
secret, err = client.Logical().Read("identity/group/id/" + italiansGroupID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
groupMap := secret.Data
|
|
found := false
|
|
for _, entityIDRaw := range groupMap["member_entity_ids"].([]interface{}) {
|
|
if entityIDRaw.(string) == entityID {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("expected entity ID %q to be part of Italians group")
|
|
}
|
|
|
|
secret, err = client.Logical().Read("identity/group/id/" + scientistsGroupID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
groupMap = secret.Data
|
|
found = false
|
|
for _, entityIDRaw := range groupMap["member_entity_ids"].([]interface{}) {
|
|
if entityIDRaw.(string) == entityID {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("expected entity ID %q to be part of Scientists group")
|
|
}
|
|
|
|
secret, err = client.Logical().Read("identity/group/id/" + devopsGroupID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
groupMap = secret.Data
|
|
found = false
|
|
for _, entityIDRaw := range groupMap["member_entity_ids"].([]interface{}) {
|
|
if entityIDRaw.(string) == entityID {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("expected entity ID %q to be part of devops group")
|
|
}
|
|
|
|
identityStore := cores[0].IdentityStore()
|
|
|
|
group, err := identityStore.MemDBGroupByID(italiansGroupID, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Remove its member entities
|
|
group.MemberEntityIDs = nil
|
|
|
|
err = identityStore.UpsertGroup(group, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
group, err = identityStore.MemDBGroupByID(italiansGroupID, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if group.MemberEntityIDs != nil {
|
|
t.Fatalf("failed to remove entity ID from the group")
|
|
}
|
|
|
|
group, err = identityStore.MemDBGroupByID(scientistsGroupID, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Remove its member entities
|
|
group.MemberEntityIDs = nil
|
|
|
|
err = identityStore.UpsertGroup(group, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
group, err = identityStore.MemDBGroupByID(scientistsGroupID, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if group.MemberEntityIDs != nil {
|
|
t.Fatalf("failed to remove entity ID from the group")
|
|
}
|
|
|
|
group, err = identityStore.MemDBGroupByID(devopsGroupID, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Remove its member entities
|
|
group.MemberEntityIDs = nil
|
|
|
|
err = identityStore.UpsertGroup(group, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
group, err = identityStore.MemDBGroupByID(devopsGroupID, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if group.MemberEntityIDs != nil {
|
|
t.Fatalf("failed to remove entity ID from the group")
|
|
}
|
|
|
|
_, err = client.Auth().Token().Renew(token, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// EntityIDs should have been added to the groups again during renewal
|
|
secret, err = client.Logical().Read("identity/group/id/" + italiansGroupID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
groupMap = secret.Data
|
|
found = false
|
|
for _, entityIDRaw := range groupMap["member_entity_ids"].([]interface{}) {
|
|
if entityIDRaw.(string) == entityID {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("expected entity ID %q to be part of Italians group")
|
|
}
|
|
|
|
secret, err = client.Logical().Read("identity/group/id/" + scientistsGroupID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
groupMap = secret.Data
|
|
found = false
|
|
for _, entityIDRaw := range groupMap["member_entity_ids"].([]interface{}) {
|
|
if entityIDRaw.(string) == entityID {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("expected entity ID %q to be part of Italians group")
|
|
}
|
|
|
|
secret, err = client.Logical().Read("identity/group/id/" + devopsGroupID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
groupMap = secret.Data
|
|
found = false
|
|
for _, entityIDRaw := range groupMap["member_entity_ids"].([]interface{}) {
|
|
if entityIDRaw.(string) == entityID {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("expected entity ID %q to be part of devops group")
|
|
}
|
|
|
|
// Remove user tesla from the devops group in LDAP backend
|
|
secret, err = client.Logical().Write("auth/ldap/users/tesla", map[string]interface{}{
|
|
"policies": "default",
|
|
"groups": "engineers",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Renewing the token now should remove its entity ID from the devops
|
|
// group
|
|
_, err = client.Auth().Token().Renew(token, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
group, err = identityStore.MemDBGroupByID(devopsGroupID, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if group.MemberEntityIDs != nil {
|
|
t.Fatalf("failed to remove entity ID from the group")
|
|
}
|
|
}
|