Unverified Commit c49cb5b3 authored by ncabatoff's avatar ncabatoff Committed by GitHub
Browse files

Use docker instead of an external LDAP server that sometimes goes down (#7522)

Showing with 349 additions and 251 deletions
+349 -251
......@@ -10,6 +10,7 @@ import (
"github.com/go-test/deep"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/helper/testhelpers/ldap"
logicaltest "github.com/hashicorp/vault/helper/testhelpers/logical"
"github.com/hashicorp/vault/sdk/helper/ldaputil"
"github.com/hashicorp/vault/sdk/helper/policyutil"
......@@ -200,7 +201,7 @@ func TestLdapAuthBackend_CaseSensitivity(t *testing.T) {
"groups": "EngineerS",
"policies": "userpolicy",
},
Path: "users/teSlA",
Path: "users/hermeS conRad",
Storage: storage,
}
resp, err = b.HandleRequest(ctx, userReq)
......@@ -213,11 +214,11 @@ func TestLdapAuthBackend_CaseSensitivity(t *testing.T) {
}
switch caseSensitive {
case true:
if keys[0] != "teSlA" {
if keys[0] != "hermeS conRad" {
t.Fatalf("bad: %s", keys[0])
}
default:
if keys[0] != "tesla" {
if keys[0] != "hermes conrad" {
t.Fatalf("bad: %s", keys[0])
}
}
......@@ -231,7 +232,7 @@ func TestLdapAuthBackend_CaseSensitivity(t *testing.T) {
"groups": "EngineerS",
"policies": "userpolicy",
},
Path: "users/tesla",
Path: "users/Hermes Conrad",
Storage: storage,
Connection: &logical.Connection{},
}
......@@ -243,9 +244,9 @@ func TestLdapAuthBackend_CaseSensitivity(t *testing.T) {
loginReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "login/tesla",
Path: "login/Hermes Conrad",
Data: map[string]interface{}{
"password": "password",
"password": "hermes",
},
Storage: storage,
Connection: &logical.Connection{},
......@@ -260,17 +261,19 @@ func TestLdapAuthBackend_CaseSensitivity(t *testing.T) {
}
}
cleanup, cfg := ldap.PrepareTestContainer(t, "latest")
defer cleanup()
configReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "config",
Data: map[string]interface{}{
// Online LDAP test server
// http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/
"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",
"url": cfg.Url,
"userattr": cfg.UserAttr,
"userdn": cfg.UserDN,
"groupdn": cfg.GroupDN,
"groupattr": cfg.GroupAttr,
"binddn": cfg.BindDN,
"bindpass": cfg.BindPassword,
},
Storage: storage,
}
......@@ -304,17 +307,19 @@ func TestLdapAuthBackend_UserPolicies(t *testing.T) {
var err error
b, storage := createBackendWithStorage(t)
cleanup, cfg := ldap.PrepareTestContainer(t, "latest")
defer cleanup()
configReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "config",
Data: map[string]interface{}{
// Online LDAP test server
// http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/
"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",
"url": cfg.Url,
"userattr": cfg.UserAttr,
"userdn": cfg.UserDN,
"groupdn": cfg.GroupDN,
"groupattr": cfg.GroupAttr,
"binddn": cfg.BindDN,
"bindpassword": cfg.BindPassword,
},
Storage: storage,
}
......@@ -343,7 +348,7 @@ func TestLdapAuthBackend_UserPolicies(t *testing.T) {
"groups": "engineers",
"policies": "userpolicy",
},
Path: "users/tesla",
Path: "users/hermes conrad",
Storage: storage,
Connection: &logical.Connection{},
}
......@@ -355,9 +360,9 @@ func TestLdapAuthBackend_UserPolicies(t *testing.T) {
loginReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "login/tesla",
Path: "login/hermes conrad",
Data: map[string]interface{}{
"password": "password",
"password": "hermes",
},
Storage: storage,
Connection: &logical.Connection{},
......@@ -376,18 +381,18 @@ func TestLdapAuthBackend_UserPolicies(t *testing.T) {
/*
* Acceptance test for LDAP Auth Method
*
* The tests here rely on a public LDAP server:
* [http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/]
* The tests here rely on a docker LDAP server:
* [https://github.com/rroemhild/docker-test-openldap]
*
* ...as well as existence of a person object, `uid=tesla,dc=example,dc=com`,
* which is a member of a group, `ou=scientists,dc=example,dc=com`
* ...as well as existence of a person object, `cn=Hermes Conrad,dc=example,dc=com`,
* which is a member of a group, `cn=admin_staff,ou=people,dc=example,dc=com`
*
* Querying the server from the command line:
* $ ldapsearch -x -H ldap://ldap.forumsys.com -b dc=example,dc=com -s sub \
* '(&(objectClass=groupOfUniqueNames)(uniqueMember=uid=tesla,dc=example,dc=com))'
*
* $ ldapsearch -x -H ldap://ldap.forumsys.com -b dc=example,dc=com -s sub uid=tesla
*/
* $ docker run --privileged -d -p 389:389 --name ldap --rm rroemhild/test-openldap
* $ ldapsearch -x -H ldap://localhost -b dc=planetexpress,dc=com -s sub uid=hermes
* $ ldapsearch -x -H ldap://localhost -b dc=planetexpress,dc=com -s sub \
'member=cn=Hermes Conrad,ou=people,dc=planetexpress,dc=com'
*/
func factory(t *testing.T) logical.Backend {
defaultLeaseTTLVal := time.Hour * 24
maxLeaseTTLVal := time.Hour * 24 * 32
......@@ -406,59 +411,67 @@ func factory(t *testing.T) logical.Backend {
func TestBackend_basic(t *testing.T) {
b := factory(t)
cleanup, cfg := ldap.PrepareTestContainer(t, "latest")
defer cleanup()
logicaltest.Test(t, logicaltest.TestCase{
CredentialBackend: b,
Steps: []logicaltest.TestStep{
testAccStepConfigUrl(t),
// Map Scientists group (from LDAP server) with foo policy
testAccStepGroup(t, "Scientists", "foo"),
testAccStepConfigUrl(t, cfg),
// Map Admin_staff group (from LDAP server) with foo policy
testAccStepGroup(t, "admin_staff", "foo"),
// Map engineers group (local) with bar policy
testAccStepGroup(t, "engineers", "bar"),
// Map tesla user with local engineers group
testAccStepUser(t, "tesla", "engineers"),
// Map hermes conrad user with local engineers group
testAccStepUser(t, "hermes conrad", "engineers"),
// Authenticate
testAccStepLogin(t, "tesla", "password"),
testAccStepLogin(t, "hermes conrad", "hermes"),
// Verify both groups mappings can be listed back
testAccStepGroupList(t, []string{"engineers", "Scientists"}),
testAccStepGroupList(t, []string{"engineers", "admin_staff"}),
// Verify user mapping can be listed back
testAccStepUserList(t, []string{"tesla"}),
testAccStepUserList(t, []string{"hermes conrad"}),
},
})
}
func TestBackend_basic_noPolicies(t *testing.T) {
b := factory(t)
cleanup, cfg := ldap.PrepareTestContainer(t, "latest")
defer cleanup()
logicaltest.Test(t, logicaltest.TestCase{
CredentialBackend: b,
Steps: []logicaltest.TestStep{
testAccStepConfigUrl(t),
testAccStepConfigUrl(t, cfg),
// Create LDAP user
testAccStepUser(t, "tesla", ""),
testAccStepUser(t, "hermes conrad", ""),
// Authenticate
testAccStepLoginNoAttachedPolicies(t, "tesla", "password"),
testAccStepUserList(t, []string{"tesla"}),
testAccStepLoginNoAttachedPolicies(t, "hermes conrad", "hermes"),
testAccStepUserList(t, []string{"hermes conrad"}),
},
})
}
func TestBackend_basic_group_noPolicies(t *testing.T) {
b := factory(t)
cleanup, cfg := ldap.PrepareTestContainer(t, "latest")
defer cleanup()
logicaltest.Test(t, logicaltest.TestCase{
CredentialBackend: b,
Steps: []logicaltest.TestStep{
testAccStepConfigUrl(t),
testAccStepConfigUrl(t, cfg),
// Create engineers group with no policies
testAccStepGroup(t, "engineers", ""),
// Map tesla user with local engineers group
testAccStepUser(t, "tesla", "engineers"),
// Map hermes conrad user with local engineers group
testAccStepUser(t, "hermes conrad", "engineers"),
// Authenticate
testAccStepLoginNoAttachedPolicies(t, "tesla", "password"),
testAccStepLoginNoAttachedPolicies(t, "hermes conrad", "hermes"),
// Verify group mapping can be listed back
testAccStepGroupList(t, []string{"engineers"}),
},
......@@ -467,45 +480,51 @@ func TestBackend_basic_group_noPolicies(t *testing.T) {
func TestBackend_basic_authbind(t *testing.T) {
b := factory(t)
cleanup, cfg := ldap.PrepareTestContainer(t, "latest")
defer cleanup()
logicaltest.Test(t, logicaltest.TestCase{
CredentialBackend: b,
Steps: []logicaltest.TestStep{
testAccStepConfigUrlWithAuthBind(t),
testAccStepGroup(t, "Scientists", "foo"),
testAccStepConfigUrlWithAuthBind(t, cfg),
testAccStepGroup(t, "admin_staff", "foo"),
testAccStepGroup(t, "engineers", "bar"),
testAccStepUser(t, "tesla", "engineers"),
testAccStepLogin(t, "tesla", "password"),
testAccStepUser(t, "hermes conrad", "engineers"),
testAccStepLogin(t, "hermes conrad", "hermes"),
},
})
}
func TestBackend_basic_discover(t *testing.T) {
b := factory(t)
cleanup, cfg := ldap.PrepareTestContainer(t, "latest")
defer cleanup()
logicaltest.Test(t, logicaltest.TestCase{
CredentialBackend: b,
Steps: []logicaltest.TestStep{
testAccStepConfigUrlWithDiscover(t),
testAccStepGroup(t, "Scientists", "foo"),
testAccStepConfigUrlWithDiscover(t, cfg),
testAccStepGroup(t, "admin_staff", "foo"),
testAccStepGroup(t, "engineers", "bar"),
testAccStepUser(t, "tesla", "engineers"),
testAccStepLogin(t, "tesla", "password"),
testAccStepUser(t, "hermes conrad", "engineers"),
testAccStepLogin(t, "hermes conrad", "hermes"),
},
})
}
func TestBackend_basic_nogroupdn(t *testing.T) {
b := factory(t)
cleanup, cfg := ldap.PrepareTestContainer(t, "latest")
defer cleanup()
logicaltest.Test(t, logicaltest.TestCase{
CredentialBackend: b,
Steps: []logicaltest.TestStep{
testAccStepConfigUrlNoGroupDN(t),
testAccStepGroup(t, "Scientists", "foo"),
testAccStepConfigUrlNoGroupDN(t, cfg),
testAccStepGroup(t, "admin_staff", "foo"),
testAccStepGroup(t, "engineers", "bar"),
testAccStepUser(t, "tesla", "engineers"),
testAccStepLoginNoGroupDN(t, "tesla", "password"),
testAccStepUser(t, "hermes conrad", "engineers"),
testAccStepLoginNoGroupDN(t, "hermes conrad", "hermes"),
},
})
}
......@@ -575,54 +594,55 @@ func TestBackend_configDefaultsAfterUpdate(t *testing.T) {
})
}
func testAccStepConfigUrl(t *testing.T) logicaltest.TestStep {
func testAccStepConfigUrl(t *testing.T, cfg *ldaputil.ConfigEntry) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: "config",
Data: map[string]interface{}{
// Online LDAP test server
// http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/
"url": "ldap://ldap.forumsys.com",
"userattr": "uid",
"userdn": "dc=example,dc=com",
"groupdn": "dc=example,dc=com",
"url": cfg.Url,
"userattr": cfg.UserAttr,
"userdn": cfg.UserDN,
"groupdn": cfg.GroupDN,
"groupattr": cfg.GroupAttr,
"binddn": cfg.BindDN,
"bindpass": cfg.BindPassword,
"case_sensitive_names": true,
"token_policies": "abc,xyz",
},
}
}
func testAccStepConfigUrlWithAuthBind(t *testing.T) logicaltest.TestStep {
func testAccStepConfigUrlWithAuthBind(t *testing.T, cfg *ldaputil.ConfigEntry) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: "config",
Data: map[string]interface{}{
// Online LDAP test server
// http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/
// In this test we also exercise multiple URL support
"url": "foobar://ldap.example.com,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",
"bindpass": "password",
"url": "foobar://ldap.example.com," + cfg.Url,
"userattr": cfg.UserAttr,
"userdn": cfg.UserDN,
"groupdn": cfg.GroupDN,
"groupattr": cfg.GroupAttr,
"binddn": cfg.BindDN,
"bindpass": cfg.BindPassword,
"case_sensitive_names": true,
"token_policies": "abc,xyz",
},
}
}
func testAccStepConfigUrlWithDiscover(t *testing.T) logicaltest.TestStep {
func testAccStepConfigUrlWithDiscover(t *testing.T, cfg *ldaputil.ConfigEntry) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: "config",
Data: map[string]interface{}{
// Online LDAP test server
// http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/
"url": "ldap://ldap.forumsys.com",
"userattr": "uid",
"userdn": "dc=example,dc=com",
"groupdn": "dc=example,dc=com",
"url": cfg.Url,
"userattr": cfg.UserAttr,
"userdn": cfg.UserDN,
"groupdn": cfg.GroupDN,
"groupattr": cfg.GroupAttr,
"binddn": cfg.BindDN,
"bindpass": cfg.BindPassword,
"discoverdn": true,
"case_sensitive_names": true,
"token_policies": "abc,xyz",
......@@ -630,16 +650,16 @@ func testAccStepConfigUrlWithDiscover(t *testing.T) logicaltest.TestStep {
}
}
func testAccStepConfigUrlNoGroupDN(t *testing.T) logicaltest.TestStep {
func testAccStepConfigUrlNoGroupDN(t *testing.T, cfg *ldaputil.ConfigEntry) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: "config",
Data: map[string]interface{}{
// Online LDAP test server
// http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/
"url": "ldap://ldap.forumsys.com",
"userattr": "uid",
"userdn": "dc=example,dc=com",
"url": cfg.Url,
"userattr": cfg.UserAttr,
"userdn": cfg.UserDN,
"binddn": cfg.BindDN,
"bindpass": cfg.BindPassword,
"discoverdn": true,
"case_sensitive_names": true,
},
......@@ -760,7 +780,7 @@ func testAccStepLogin(t *testing.T, user string, pass string) logicaltest.TestSt
},
Unauthenticated: true,
// Verifies user tesla maps to groups via local group (engineers) as well as remote group (Scientists)
// Verifies user hermes conrad maps to groups via local group (engineers) as well as remote group (Scientists)
Check: logicaltest.TestCheckAuth([]string{"abc", "bar", "default", "foo", "xyz"}),
}
}
......@@ -774,7 +794,7 @@ func testAccStepLoginNoAttachedPolicies(t *testing.T, user string, pass string)
},
Unauthenticated: true,
// Verifies user tesla maps to groups via local group (engineers) as well as remote group (Scientists)
// Verifies user hermes conrad maps to groups via local group (engineers) as well as remote group (Scientists)
Check: logicaltest.TestCheckAuth([]string{"abc", "default", "xyz"}),
}
}
......@@ -856,16 +876,19 @@ func TestLdapAuthBackend_ConfigUpgrade(t *testing.T) {
ctx := context.Background()
// Write in some initial config
cleanup, cfg := ldap.PrepareTestContainer(t, "latest")
defer cleanup()
configReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "config",
Data: 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",
"url": cfg.Url,
"userattr": cfg.UserAttr,
"userdn": cfg.UserDN,
"groupdn": cfg.GroupDN,
"groupattr": cfg.GroupAttr,
"binddn": cfg.BindDN,
"bindpass": cfg.BindPassword,
"token_period": "5m",
"token_explicit_max_ttl": "24h",
},
......@@ -894,14 +917,15 @@ func TestLdapAuthBackend_ConfigUpgrade(t *testing.T) {
TokenExplicitMaxTTL: 24 * time.Hour,
},
ConfigEntry: &ldaputil.ConfigEntry{
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",
Url: cfg.Url,
UserAttr: cfg.UserAttr,
UserDN: cfg.UserDN,
GroupDN: cfg.GroupDN,
GroupAttr: cfg.GroupAttr,
BindDN: cfg.BindDN,
BindPassword: cfg.BindPassword,
GroupFilter: defParams.GroupFilter,
DenyNullBind: defParams.DenyNullBind,
GroupAttr: defParams.GroupAttr,
TLSMinVersion: defParams.TLSMinVersion,
TLSMaxVersion: defParams.TLSMaxVersion,
CaseSensitiveNames: falseBool,
......
......@@ -40,6 +40,7 @@ require (
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/go-errors/errors v1.0.1
github.com/go-ldap/ldap v3.0.2+incompatible
github.com/go-sql-driver/mysql v1.4.1
github.com/go-test/deep v1.0.2
github.com/gocql/gocql v0.0.0-20190402132108-0e1d5de854df
......
package ldap
import (
"fmt"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/helper/testhelpers/docker"
"github.com/hashicorp/vault/sdk/helper/ldaputil"
"github.com/ory/dockertest"
"testing"
)
func PrepareTestContainer(t *testing.T, version string) (cleanup func(), cfg *ldaputil.ConfigEntry) {
pool, err := dockertest.NewPool("")
if err != nil {
t.Fatalf("Failed to connect to docker: %s", err)
}
dockerOptions := &dockertest.RunOptions{
Repository: "rroemhild/test-openldap",
Tag: version,
Privileged: true,
//Env: []string{"LDAP_DEBUG_LEVEL=384"},
}
resource, err := pool.RunWithOptions(dockerOptions)
if err != nil {
t.Fatalf("Could not start local LDAP %s docker container: %s", version, err)
}
cleanup = func() {
docker.CleanupResource(t, pool, resource)
}
//pool.MaxWait = time.Second
// exponential backoff-retry
if err = pool.Retry(func() error {
logger := hclog.New(nil)
client := ldaputil.Client{
LDAP: ldaputil.NewLDAP(),
Logger: logger,
}
cfg = new(ldaputil.ConfigEntry)
cfg.Url = fmt.Sprintf("ldap://localhost:%s", resource.GetPort("389/tcp"))
cfg.UserDN = "ou=people,dc=planetexpress,dc=com"
cfg.UserAttr = "cn"
cfg.BindDN = "cn=admin,dc=planetexpress,dc=com"
cfg.BindPassword = "GoodNewsEveryone"
cfg.GroupDN = "ou=people,dc=planetexpress,dc=com"
cfg.GroupAttr = "memberOf"
conn, err := client.DialLDAP(cfg)
if err != nil {
return err
}
defer conn.Close()
if _, err := client.GetUserBindDN(cfg, conn, "Philip J. Fry"); err != nil {
return err
}
return nil
}); err != nil {
cleanup()
t.Fatalf("Could not connect to docker: %s", err)
}
return cleanup, cfg
}
......@@ -4,6 +4,7 @@ import (
"testing"
"github.com/hashicorp/vault/api"
ldaphelper "github.com/hashicorp/vault/helper/testhelpers/ldap"
vaulthttp "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"
......@@ -178,13 +179,18 @@ func TestIdentityStore_ExternalGroupMembershipsAcrossMounts(t *testing.T) {
}
ldapMountAccessor1 := auths["ldap/"].Accessor
cleanup, cfg := ldaphelper.PrepareTestContainer(t, "latest")
defer cleanup()
// 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",
secret, err := client.Logical().Write("auth/ldap/config", map[string]interface{}{
"url": cfg.Url,
"userattr": cfg.UserAttr,
"userdn": cfg.UserDN,
"groupdn": cfg.GroupDN,
"groupattr": cfg.GroupAttr,
"binddn": cfg.BindDN,
"bindpass": cfg.BindPassword,
})
if err != nil {
t.Fatal(err)
......@@ -199,7 +205,7 @@ func TestIdentityStore_ExternalGroupMembershipsAcrossMounts(t *testing.T) {
}
// Tie the group to a user
_, err = client.Logical().Write("auth/ldap/users/tesla", map[string]interface{}{
_, err = client.Logical().Write("auth/ldap/users/hermes conrad", map[string]interface{}{
"policies": "default",
"groups": "testgroup1",
})
......@@ -208,7 +214,7 @@ func TestIdentityStore_ExternalGroupMembershipsAcrossMounts(t *testing.T) {
}
// Create an external group
secret, err := client.Logical().Write("identity/group", map[string]interface{}{
secret, err = client.Logical().Write("identity/group", map[string]interface{}{
"type": "external",
})
if err != nil {
......@@ -227,8 +233,8 @@ func TestIdentityStore_ExternalGroupMembershipsAcrossMounts(t *testing.T) {
}
// Login using LDAP
secret, err = client.Logical().Write("auth/ldap/login/tesla", map[string]interface{}{
"password": "password",
secret, err = client.Logical().Write("auth/ldap/login/hermes conrad", map[string]interface{}{
"password": "hermes",
})
if err != nil {
t.Fatal(err)
......@@ -264,10 +270,10 @@ func TestIdentityStore_ExternalGroupMembershipsAcrossMounts(t *testing.T) {
}
ldapMountAccessor2 := auths["ldap2/"].Accessor
// Create an entity-alias asserting that the user "tesla" from the first
// Create an entity-alias asserting that the user "hermes conrad" from the first
// and second LDAP mounts as the same.
_, err = client.Logical().Write("identity/entity-alias", map[string]interface{}{
"name": "tesla",
"name": "hermes conrad",
"mount_accessor": ldapMountAccessor2,
"canonical_id": entityID,
})
......@@ -275,13 +281,18 @@ func TestIdentityStore_ExternalGroupMembershipsAcrossMounts(t *testing.T) {
t.Fatal(err)
}
// Configure second LDAP auth
_, err = client.Logical().Write("auth/ldap2/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",
cleanup2, cfg2 := ldaphelper.PrepareTestContainer(t, "latest")
defer cleanup2()
// Configure LDAP auth
secret, err = client.Logical().Write("auth/ldap2/config", map[string]interface{}{
"url": cfg2.Url,
"userattr": cfg2.UserAttr,
"userdn": cfg2.UserDN,
"groupdn": cfg2.GroupDN,
"groupattr": cfg2.GroupAttr,
"binddn": cfg2.BindDN,
"bindpass": cfg2.BindPassword,
})
if err != nil {
t.Fatal(err)
......@@ -296,7 +307,7 @@ func TestIdentityStore_ExternalGroupMembershipsAcrossMounts(t *testing.T) {
}
// Create a user in second LDAP auth
_, err = client.Logical().Write("auth/ldap2/users/tesla", map[string]interface{}{
_, err = client.Logical().Write("auth/ldap2/users/hermes conrad", map[string]interface{}{
"policies": "default",
"groups": "testgroup2",
})
......@@ -324,8 +335,8 @@ func TestIdentityStore_ExternalGroupMembershipsAcrossMounts(t *testing.T) {
}
// Login using second LDAP
_, err = client.Logical().Write("auth/ldap2/login/tesla", map[string]interface{}{
"password": "password",
_, err = client.Logical().Write("auth/ldap2/login/hermes conrad", map[string]interface{}{
"password": "hermes",
})
if err != nil {
t.Fatal(err)
......
package identity
import (
"github.com/go-ldap/ldap"
"github.com/hashicorp/vault/sdk/helper/ldaputil"
"testing"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/builtin/credential/ldap"
ldapcred "github.com/hashicorp/vault/builtin/credential/ldap"
"github.com/hashicorp/vault/helper/namespace"
ldaphelper "github.com/hashicorp/vault/helper/testhelpers/ldap"
vaulthttp "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"
......@@ -19,7 +22,7 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
DisableCache: true,
Logger: log.NewNullLogger(),
CredentialBackends: map[string]logical.Factory{
"ldap": ldap.Factory,
"ldap": ldapcred.Factory,
},
}
......@@ -52,21 +55,21 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
secret, err := client.Logical().Write("identity/group", map[string]interface{}{
"type": "external",
"name": "ldap_Italians",
"name": "ldap_ship_crew",
})
if err != nil {
t.Fatal(err)
}
italiansGroupID := secret.Data["id"].(string)
shipCrewGroupID := secret.Data["id"].(string)
secret, err = client.Logical().Write("identity/group", map[string]interface{}{
"type": "external",
"name": "ldap_Scientists",
"name": "ldap_admin_staff",
})
if err != nil {
t.Fatal(err)
}
scientistsGroupID := secret.Data["id"].(string)
adminStaffGroupID := secret.Data["id"].(string)
secret, err = client.Logical().Write("identity/group", map[string]interface{}{
"type": "external",
......@@ -78,8 +81,8 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
devopsGroupID := secret.Data["id"].(string)
secret, err = client.Logical().Write("identity/group-alias", map[string]interface{}{
"name": "Italians",
"canonical_id": italiansGroupID,
"name": "ship_crew",
"canonical_id": shipCrewGroupID,
"mount_accessor": accessor,
})
if err != nil {
......@@ -87,8 +90,8 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
}
secret, err = client.Logical().Write("identity/group-alias", map[string]interface{}{
"name": "Scientists",
"canonical_id": scientistsGroupID,
"name": "admin_staff",
"canonical_id": adminStaffGroupID,
"mount_accessor": accessor,
})
if err != nil {
......@@ -104,35 +107,40 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
t.Fatal(err)
}
secret, err = client.Logical().Read("identity/group/id/" + italiansGroupID)
secret, err = client.Logical().Read("identity/group/id/" + shipCrewGroupID)
if err != nil {
t.Fatal(err)
}
aliasMap := secret.Data["alias"].(map[string]interface{})
if aliasMap["canonical_id"] != italiansGroupID ||
aliasMap["name"] != "Italians" ||
if aliasMap["canonical_id"] != shipCrewGroupID ||
aliasMap["name"] != "ship_crew" ||
aliasMap["mount_accessor"] != accessor {
t.Fatalf("bad: group alias: %#v\n", aliasMap)
}
secret, err = client.Logical().Read("identity/group/id/" + scientistsGroupID)
secret, err = client.Logical().Read("identity/group/id/" + adminStaffGroupID)
if err != nil {
t.Fatal(err)
}
aliasMap = secret.Data["alias"].(map[string]interface{})
if aliasMap["canonical_id"] != scientistsGroupID ||
aliasMap["name"] != "Scientists" ||
if aliasMap["canonical_id"] != adminStaffGroupID ||
aliasMap["name"] != "admin_staff" ||
aliasMap["mount_accessor"] != accessor {
t.Fatalf("bad: group alias: %#v\n", aliasMap)
}
// Configure LDAP auth backend
cleanup, cfg := ldaphelper.PrepareTestContainer(t, "latest")
defer cleanup()
// Configure LDAP auth
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",
"url": cfg.Url,
"userattr": cfg.UserAttr,
"userdn": cfg.UserDN,
"groupdn": cfg.GroupDN,
"groupattr": cfg.GroupAttr,
"binddn": cfg.BindDN,
"bindpass": cfg.BindPassword,
})
if err != nil {
t.Fatal(err)
......@@ -155,7 +163,7 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
}
// Create a local user in LDAP
secret, err = client.Logical().Write("auth/ldap/users/tesla", map[string]interface{}{
secret, err = client.Logical().Write("auth/ldap/users/hermes conrad", map[string]interface{}{
"policies": "default",
"groups": "engineers,devops",
})
......@@ -164,8 +172,8 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
}
// Login with LDAP and create a token
secret, err = client.Logical().Write("auth/ldap/login/tesla", map[string]interface{}{
"password": "password",
secret, err = client.Logical().Write("auth/ldap/login/hermes conrad", map[string]interface{}{
"password": "hermes",
})
if err != nil {
t.Fatal(err)
......@@ -179,56 +187,80 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
}
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
// Re-read the admin_staff, ship_crew and devops group. This entity ID should have
// been added to admin_staff but not ship_crew.
assertMember := func(groupName, groupID string, expectFound bool) {
secret, err = client.Logical().Read("identity/group/id/" + groupID)
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 != expectFound {
negation := ""
if !expectFound {
negation = "not "
}
t.Fatalf("expected entity ID %q to %sbe part of %q group", entityID, negation, groupName)
}
}
if !found {
t.Fatalf("expected entity ID %q to be part of Italians group", entityID)
}
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
assertMember("ship_crew", shipCrewGroupID, false)
assertMember("admin_staff", adminStaffGroupID, true)
assertMember("devops", devopsGroupID, true)
assertMember("engineer", devopsGroupID, true)
// Now add Hermes to ship_crew
{
logger := log.New(nil)
ldapClient := ldaputil.Client{LDAP: ldaputil.NewLDAP(), Logger: logger}
// LDAP server won't accept changes unless we connect with TLS. This
// isn't the default config returned by PrepareTestContainer because
// the Vault LDAP backend won't work with it, even with InsecureTLS,
// because the ServerName should be planetexpress.com and not localhost.
conn, err := ldapClient.DialLDAP(cfg)
if err != nil {
t.Fatal(err)
}
defer conn.Close()
err = conn.Bind(cfg.BindDN, cfg.BindPassword)
if err != nil {
t.Fatal(err)
}
hermesDn := "cn=Hermes Conrad,ou=people,dc=planetexpress,dc=com"
shipCrewDn := "cn=ship_crew,ou=people,dc=planetexpress,dc=com"
ldapreq := ldap.ModifyRequest{DN: shipCrewDn}
ldapreq.Add("member", []string{hermesDn})
err = conn.Modify(&ldapreq)
if err != nil {
t.Fatal(err)
}
}
if !found {
t.Fatalf("expected entity ID %q to be part of Scientists group", entityID)
}
secret, err = client.Logical().Read("identity/group/id/" + devopsGroupID)
// Re-login with LDAP
secret, err = client.Logical().Write("auth/ldap/login/hermes conrad", map[string]interface{}{
"password": "hermes",
})
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", entityID)
}
// Hermes should now be in ship_crew external group
assertMember("ship_crew", shipCrewGroupID, true)
assertMember("admin_staff", adminStaffGroupID, true)
assertMember("devops", devopsGroupID, true)
assertMember("engineer", devopsGroupID, true)
identityStore := cores[0].IdentityStore()
group, err := identityStore.MemDBGroupByID(italiansGroupID, true)
group, err := identityStore.MemDBGroupByID(shipCrewGroupID, true)
if err != nil {
t.Fatal(err)
}
......@@ -243,7 +275,7 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
t.Fatal(err)
}
group, err = identityStore.MemDBGroupByID(italiansGroupID, true)
group, err = identityStore.MemDBGroupByID(shipCrewGroupID, true)
if err != nil {
t.Fatal(err)
}
......@@ -251,7 +283,7 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
t.Fatalf("failed to remove entity ID from the group")
}
group, err = identityStore.MemDBGroupByID(scientistsGroupID, true)
group, err = identityStore.MemDBGroupByID(adminStaffGroupID, true)
if err != nil {
t.Fatal(err)
}
......@@ -264,7 +296,7 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
t.Fatal(err)
}
group, err = identityStore.MemDBGroupByID(scientistsGroupID, true)
group, err = identityStore.MemDBGroupByID(adminStaffGroupID, true)
if err != nil {
t.Fatal(err)
}
......@@ -298,55 +330,13 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) {
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", entityID)
}
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", entityID)
}
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", entityID)
}
assertMember("ship_crew", shipCrewGroupID, true)
assertMember("admin_staff", adminStaffGroupID, true)
assertMember("devops", devopsGroupID, true)
assertMember("engineer", devopsGroupID, true)
// Remove user tesla from the devops group in LDAP backend
secret, err = client.Logical().Write("auth/ldap/users/tesla", map[string]interface{}{
// Remove user hermes conrad from the devops group in LDAP backend
secret, err = client.Logical().Write("auth/ldap/users/hermes conrad", map[string]interface{}{
"policies": "default",
"groups": "engineers",
})
......
......@@ -12,6 +12,7 @@ import (
"github.com/hashicorp/vault/api"
credLdap "github.com/hashicorp/vault/builtin/credential/ldap"
credUserpass "github.com/hashicorp/vault/builtin/credential/userpass"
"github.com/hashicorp/vault/helper/testhelpers/ldap"
vaulthttp "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/logical"
......@@ -127,13 +128,18 @@ func TestTokenStore_IdentityPolicies(t *testing.T) {
t.Fatal(err)
}
cleanup, cfg := ldap.PrepareTestContainer(t, "latest")
defer cleanup()
// 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",
"url": cfg.Url,
"userattr": cfg.UserAttr,
"userdn": cfg.UserDN,
"groupdn": cfg.GroupDN,
"groupattr": cfg.GroupAttr,
"binddn": cfg.BindDN,
"bindpass": cfg.BindPassword,
})
if err != nil {
t.Fatal(err)
......@@ -149,7 +155,7 @@ func TestTokenStore_IdentityPolicies(t *testing.T) {
// Create user in LDAP auth. We add two groups, but we should filter out
// the ones that don't match aliases later (we will check for this)
_, err = client.Logical().Write("auth/ldap/users/tesla", map[string]interface{}{
_, err = client.Logical().Write("auth/ldap/users/hermes conrad", map[string]interface{}{
"policies": "default",
"groups": "testgroup1,testgroup2",
})
......@@ -158,8 +164,8 @@ func TestTokenStore_IdentityPolicies(t *testing.T) {
}
// Login using LDAP
secret, err := client.Logical().Write("auth/ldap/login/tesla", map[string]interface{}{
"password": "password",
secret, err := client.Logical().Write("auth/ldap/login/hermes conrad", map[string]interface{}{
"password": "hermes",
})
if err != nil {
t.Fatal(err)
......@@ -327,8 +333,8 @@ func TestTokenStore_IdentityPolicies(t *testing.T) {
// Log in and get a new token, then renew it. See issue #4829. The logic is
// continued after the next block.
secret, err = client.Logical().Write("auth/ldap/login/tesla", map[string]interface{}{
"password": "password",
secret, err = client.Logical().Write("auth/ldap/login/hermes conrad", map[string]interface{}{
"password": "hermes",
})
if err != nil {
t.Fatal(err)
......@@ -338,12 +344,12 @@ func TestTokenStore_IdentityPolicies(t *testing.T) {
// Check that the lease for the token contains only the single group; this
// should be true for both as one was fresh and the other was a renew
// (which is why we do the renew check on the 4839 token after this block)
secret, err = client.Logical().List("sys/raw/sys/expire/id/auth/ldap/login/tesla/")
secret, err = client.Logical().List("sys/raw/sys/expire/id/auth/ldap/login/hermes conrad/")
if err != nil {
t.Fatal(err)
}
for _, key := range secret.Data["keys"].([]interface{}) {
secret, err := client.Logical().Read("sys/raw/sys/expire/id/auth/ldap/login/tesla/" + key.(string))
secret, err := client.Logical().Read("sys/raw/sys/expire/id/auth/ldap/login/hermes conrad/" + key.(string))
if err != nil {
t.Fatal(err)
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment