From 91b7d03bfbfb067518da0e0e3a0e8b5a33e0787a Mon Sep 17 00:00:00 2001 From: Nick Cabatoff Date: Thu, 26 Sep 2019 13:46:53 -0400 Subject: [PATCH 1/8] Switch from using an external LDAP server that sometimes goes down, to a local (docker) LDAP server. The schema and data changes too, unfortunately. --- builtin/credential/ldap/backend_test.go | 224 +++++++++++++----------- helper/testhelpers/ldap/ldaphelper.go | 64 +++++++ sdk/helper/ldaputil/client.go | 2 +- 3 files changed, 190 insertions(+), 100 deletions(-) create mode 100644 helper/testhelpers/ldap/ldaphelper.go diff --git a/builtin/credential/ldap/backend_test.go b/builtin/credential/ldap/backend_test.go index f8f8b6583a99..098009cd10f1 100644 --- a/builtin/credential/ldap/backend_test.go +++ b/builtin/credential/ldap/backend_test.go @@ -3,6 +3,7 @@ package ldap import ( "context" "fmt" + "github.com/hashicorp/vault/helper/testhelpers/ldap" "reflect" "sort" "testing" @@ -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,13 +381,14 @@ 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: + * TODO * $ ldapsearch -x -H ldap://ldap.forumsys.com -b dc=example,dc=com -s sub \ * '(&(objectClass=groupOfUniqueNames)(uniqueMember=uid=tesla,dc=example,dc=com))' * @@ -406,59 +412,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 +481,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 +595,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 +651,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 +781,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 +795,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,20 +877,24 @@ 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", }, - Storage: storage, + Storage: storage, + // TODO remove? Connection: &logical.Connection{}, } resp, err = b.HandleRequest(ctx, configReq) @@ -894,14 +919,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, diff --git a/helper/testhelpers/ldap/ldaphelper.go b/helper/testhelpers/ldap/ldaphelper.go new file mode 100644 index 000000000000..7ae5dbe96ef2 --- /dev/null +++ b/helper/testhelpers/ldap/ldaphelper.go @@ -0,0 +1,64 @@ +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, + } + 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) + } + + retAddress := fmt.Sprintf("localhost:%s", resource.GetPort("389/tcp")) + + //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 = "ldap://" + retAddress + 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() + + _, err = client.GetUserBindDN(cfg, conn, "Philip J. Fry") + return err + }); err != nil { + cleanup() + t.Fatalf("Could not connect to docker: %s", err) + } + return cleanup, cfg +} diff --git a/sdk/helper/ldaputil/client.go b/sdk/helper/ldaputil/client.go index dff8534d7a1c..c1425b729ade 100644 --- a/sdk/helper/ldaputil/client.go +++ b/sdk/helper/ldaputil/client.go @@ -127,7 +127,7 @@ func (c *Client) GetUserBindDN(cfg *ConfigEntry, conn Connection, username strin return bindDN, errwrap.Wrapf("LDAP search for binddn failed: {{err}}", err) } if len(result.Entries) != 1 { - return bindDN, fmt.Errorf("LDAP search for binddn 0 or not unique") + return bindDN, fmt.Errorf("LDAP search for binddn 0 or not unique (%d results)", len(result.Entries)) } bindDN = result.Entries[0].DN } else { From f47223fadf9324fa1c0973a4867e991eca978723 Mon Sep 17 00:00:00 2001 From: Nick Cabatoff Date: Mon, 30 Sep 2019 09:08:17 -0400 Subject: [PATCH 2/8] Convert token_test to use the docker ldap server. Attempt to convert TestIdentityStore_Integ_GroupAliases to use the docker ldap server, but it's not working yet. The first obstacle was that it expects a user to exist in two external group: Scientists and Italians. There are no users in the new ldap server's data who belong to two ldap groups. One thing Becca was saying she hoped the docker ldap server would allow us is to make changes to the LDAP data. So I decided to modify the test such that it first sees a user in a single LDAP group, then once we add the user to a second group, upon re-logging in we see them in that identity group as well. This proved not to be so easy. I got LDAP Result Code 8 "Strong Auth Required": modifications require authentication Some googling suggested this would be fixed if we used TLS. This was a bit of an adventure since they use a self-signed cert, but eventually I got that working, at least in the context of a test: I wasn't able to get the LDAP backend itself to be happy with that, which is why PrepareTestContainer now returns two ldaputil.ConfigEntry structs. Anyway, that turned out not to be the right fix, or possible just insufficient. I'm still getting the same error, but now I think it's because the admin user hasn't been granted write privs. I'm not certain how to do that without building a new docker image, and if that is required I might revisit which docker image we use. --- builtin/credential/ldap/backend_test.go | 24 +- helper/testhelpers/ldap/ldaphelper.go | 12 +- .../external_tests/identity/identity_test.go | 213 ++++++++---------- vault/external_tests/token/token_test.go | 30 ++- 4 files changed, 136 insertions(+), 143 deletions(-) diff --git a/builtin/credential/ldap/backend_test.go b/builtin/credential/ldap/backend_test.go index 098009cd10f1..b1691def0fcc 100644 --- a/builtin/credential/ldap/backend_test.go +++ b/builtin/credential/ldap/backend_test.go @@ -3,7 +3,6 @@ package ldap import ( "context" "fmt" - "github.com/hashicorp/vault/helper/testhelpers/ldap" "reflect" "sort" "testing" @@ -11,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" @@ -261,7 +261,7 @@ func TestLdapAuthBackend_CaseSensitivity(t *testing.T) { } } - cleanup, cfg := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") defer cleanup() configReq := &logical.Request{ Operation: logical.UpdateOperation, @@ -307,7 +307,7 @@ func TestLdapAuthBackend_UserPolicies(t *testing.T) { var err error b, storage := createBackendWithStorage(t) - cleanup, cfg := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") defer cleanup() configReq := &logical.Request{ Operation: logical.UpdateOperation, @@ -390,10 +390,10 @@ func TestLdapAuthBackend_UserPolicies(t *testing.T) { * Querying the server from the command line: * TODO * $ ldapsearch -x -H ldap://ldap.forumsys.com -b dc=example,dc=com -s sub \ - * '(&(objectClass=groupOfUniqueNames)(uniqueMember=uid=tesla,dc=example,dc=com))' + '(&(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 - */ +*/ func factory(t *testing.T) logical.Backend { defaultLeaseTTLVal := time.Hour * 24 maxLeaseTTLVal := time.Hour * 24 * 32 @@ -412,7 +412,7 @@ func factory(t *testing.T) logical.Backend { func TestBackend_basic(t *testing.T) { b := factory(t) - cleanup, cfg := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -442,7 +442,7 @@ func TestBackend_basic(t *testing.T) { func TestBackend_basic_noPolicies(t *testing.T) { b := factory(t) - cleanup, cfg := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -460,7 +460,7 @@ func TestBackend_basic_noPolicies(t *testing.T) { func TestBackend_basic_group_noPolicies(t *testing.T) { b := factory(t) - cleanup, cfg := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -481,7 +481,7 @@ func TestBackend_basic_group_noPolicies(t *testing.T) { func TestBackend_basic_authbind(t *testing.T) { b := factory(t) - cleanup, cfg := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -498,7 +498,7 @@ func TestBackend_basic_authbind(t *testing.T) { func TestBackend_basic_discover(t *testing.T) { b := factory(t) - cleanup, cfg := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -515,7 +515,7 @@ func TestBackend_basic_discover(t *testing.T) { func TestBackend_basic_nogroupdn(t *testing.T) { b := factory(t) - cleanup, cfg := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -877,7 +877,7 @@ func TestLdapAuthBackend_ConfigUpgrade(t *testing.T) { ctx := context.Background() - cleanup, cfg := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") defer cleanup() configReq := &logical.Request{ Operation: logical.UpdateOperation, diff --git a/helper/testhelpers/ldap/ldaphelper.go b/helper/testhelpers/ldap/ldaphelper.go index 7ae5dbe96ef2..fa902772284c 100644 --- a/helper/testhelpers/ldap/ldaphelper.go +++ b/helper/testhelpers/ldap/ldaphelper.go @@ -9,7 +9,7 @@ import ( "testing" ) -func PrepareTestContainer(t *testing.T, version string) (cleanup func(), cfg *ldaputil.ConfigEntry) { +func PrepareTestContainer(t *testing.T, version string) (cleanup func(), cfg, cfgtls *ldaputil.ConfigEntry) { pool, err := dockertest.NewPool("") if err != nil { t.Fatalf("Failed to connect to docker: %s", err) @@ -29,8 +29,6 @@ func PrepareTestContainer(t *testing.T, version string) (cleanup func(), cfg *ld docker.CleanupResource(t, pool, resource) } - retAddress := fmt.Sprintf("localhost:%s", resource.GetPort("389/tcp")) - //pool.MaxWait = time.Second // exponential backoff-retry if err = pool.Retry(func() error { @@ -41,7 +39,7 @@ func PrepareTestContainer(t *testing.T, version string) (cleanup func(), cfg *ld } cfg = new(ldaputil.ConfigEntry) - cfg.Url = "ldap://" + retAddress + 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" @@ -60,5 +58,9 @@ func PrepareTestContainer(t *testing.T, version string) (cleanup func(), cfg *ld cleanup() t.Fatalf("Could not connect to docker: %s", err) } - return cleanup, cfg + + cfgcopy := *cfg + cfgcopy.InsecureTLS = true + cfgcopy.Url = fmt.Sprintf("ldaps://localhost:%s", resource.GetPort("636/tcp")) + return cleanup, cfg, &cfgcopy } diff --git a/vault/external_tests/identity/identity_test.go b/vault/external_tests/identity/identity_test.go index 8b499cb03414..f89adcc0b843 100644 --- a/vault/external_tests/identity/identity_test.go +++ b/vault/external_tests/identity/identity_test.go @@ -1,12 +1,15 @@ 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, cfgtls := 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,75 @@ 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(cfgtls) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + + 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 +270,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 +278,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 +291,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 +325,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", }) diff --git a/vault/external_tests/token/token_test.go b/vault/external_tests/token/token_test.go index ac0582ffa6ca..70198d1376f8 100644 --- a/vault/external_tests/token/token_test.go +++ b/vault/external_tests/token/token_test.go @@ -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) } From 2ceb4edcc86dfc1c99202f20e886f068e01e91e4 Mon Sep 17 00:00:00 2001 From: Nick Cabatoff Date: Mon, 21 Oct 2019 11:00:49 -0400 Subject: [PATCH 3/8] Fix authentication. --- helper/testhelpers/ldap/ldaphelper.go | 1 + vault/external_tests/identity/identity_test.go | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/helper/testhelpers/ldap/ldaphelper.go b/helper/testhelpers/ldap/ldaphelper.go index fa902772284c..b7be01fbf7a6 100644 --- a/helper/testhelpers/ldap/ldaphelper.go +++ b/helper/testhelpers/ldap/ldaphelper.go @@ -19,6 +19,7 @@ func PrepareTestContainer(t *testing.T, version string) (cleanup func(), cfg, cf Repository: "rroemhild/test-openldap", Tag: version, Privileged: true, + //Env: []string{"LDAP_DEBUG_LEVEL=384"}, } resource, err := pool.RunWithOptions(dockerOptions) if err != nil { diff --git a/vault/external_tests/identity/identity_test.go b/vault/external_tests/identity/identity_test.go index f89adcc0b843..dec6fa422e69 100644 --- a/vault/external_tests/identity/identity_test.go +++ b/vault/external_tests/identity/identity_test.go @@ -229,6 +229,11 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) { } 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} From e391f4b699e113d1a3628e71b66c4bcfdbe660b1 Mon Sep 17 00:00:00 2001 From: Nick Cabatoff Date: Mon, 21 Oct 2019 11:41:35 -0400 Subject: [PATCH 4/8] Convert another test to use docker ldap. --- go.mod | 2 + sdk/go.mod | 1 + vault/external_tests/identity/groups_test.go | 55 ++++++++++++-------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/go.mod b/go.mod index befb49285a50..718e9efab02a 100644 --- a/go.mod +++ b/go.mod @@ -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 @@ -91,6 +92,7 @@ require ( github.com/joyent/triton-go v0.0.0-20190112182421-51ffac552869 github.com/keybase/go-crypto v0.0.0-20190403132359-d65b6b94177f github.com/kr/pretty v0.1.0 + github.com/kr/pty v1.1.3 // indirect github.com/kr/text v0.1.0 github.com/lib/pq v1.2.0 github.com/mattn/go-colorable v0.1.2 diff --git a/sdk/go.mod b/sdk/go.mod index 69d135bf8f53..cd382d9e9b8a 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -31,6 +31,7 @@ require ( golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 // indirect golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db // indirect + google.golang.org/appengine v1.4.0 // indirect google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 // indirect google.golang.org/grpc v1.22.0 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect diff --git a/vault/external_tests/identity/groups_test.go b/vault/external_tests/identity/groups_test.go index 90996ee4190c..4d43933e536a 100644 --- a/vault/external_tests/identity/groups_test.go +++ b/vault/external_tests/identity/groups_test.go @@ -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) From e74916f5c6b7c96899d98082863454c65ca2f4df Mon Sep 17 00:00:00 2001 From: Nick Cabatoff Date: Mon, 21 Oct 2019 13:49:30 -0400 Subject: [PATCH 5/8] Remove unnecessary LDAP-TLS option. --- builtin/credential/ldap/backend_test.go | 18 +++++++++--------- helper/testhelpers/ldap/ldaphelper.go | 7 ++----- vault/external_tests/identity/groups_test.go | 4 ++-- vault/external_tests/identity/identity_test.go | 4 ++-- vault/external_tests/token/token_test.go | 2 +- 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/builtin/credential/ldap/backend_test.go b/builtin/credential/ldap/backend_test.go index b1691def0fcc..af6b653fe098 100644 --- a/builtin/credential/ldap/backend_test.go +++ b/builtin/credential/ldap/backend_test.go @@ -261,7 +261,7 @@ func TestLdapAuthBackend_CaseSensitivity(t *testing.T) { } } - cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg := ldap.PrepareTestContainer(t, "latest") defer cleanup() configReq := &logical.Request{ Operation: logical.UpdateOperation, @@ -307,7 +307,7 @@ func TestLdapAuthBackend_UserPolicies(t *testing.T) { var err error b, storage := createBackendWithStorage(t) - cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg := ldap.PrepareTestContainer(t, "latest") defer cleanup() configReq := &logical.Request{ Operation: logical.UpdateOperation, @@ -412,7 +412,7 @@ func factory(t *testing.T) logical.Backend { func TestBackend_basic(t *testing.T) { b := factory(t) - cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -442,7 +442,7 @@ func TestBackend_basic(t *testing.T) { func TestBackend_basic_noPolicies(t *testing.T) { b := factory(t) - cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -460,7 +460,7 @@ func TestBackend_basic_noPolicies(t *testing.T) { func TestBackend_basic_group_noPolicies(t *testing.T) { b := factory(t) - cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -481,7 +481,7 @@ func TestBackend_basic_group_noPolicies(t *testing.T) { func TestBackend_basic_authbind(t *testing.T) { b := factory(t) - cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -498,7 +498,7 @@ func TestBackend_basic_authbind(t *testing.T) { func TestBackend_basic_discover(t *testing.T) { b := factory(t) - cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -515,7 +515,7 @@ func TestBackend_basic_discover(t *testing.T) { func TestBackend_basic_nogroupdn(t *testing.T) { b := factory(t) - cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg := ldap.PrepareTestContainer(t, "latest") defer cleanup() logicaltest.Test(t, logicaltest.TestCase{ @@ -877,7 +877,7 @@ func TestLdapAuthBackend_ConfigUpgrade(t *testing.T) { ctx := context.Background() - cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg := ldap.PrepareTestContainer(t, "latest") defer cleanup() configReq := &logical.Request{ Operation: logical.UpdateOperation, diff --git a/helper/testhelpers/ldap/ldaphelper.go b/helper/testhelpers/ldap/ldaphelper.go index b7be01fbf7a6..c6dfb41b145a 100644 --- a/helper/testhelpers/ldap/ldaphelper.go +++ b/helper/testhelpers/ldap/ldaphelper.go @@ -9,7 +9,7 @@ import ( "testing" ) -func PrepareTestContainer(t *testing.T, version string) (cleanup func(), cfg, cfgtls *ldaputil.ConfigEntry) { +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) @@ -60,8 +60,5 @@ func PrepareTestContainer(t *testing.T, version string) (cleanup func(), cfg, cf t.Fatalf("Could not connect to docker: %s", err) } - cfgcopy := *cfg - cfgcopy.InsecureTLS = true - cfgcopy.Url = fmt.Sprintf("ldaps://localhost:%s", resource.GetPort("636/tcp")) - return cleanup, cfg, &cfgcopy + return cleanup, cfg } diff --git a/vault/external_tests/identity/groups_test.go b/vault/external_tests/identity/groups_test.go index 4d43933e536a..12dd29a51f55 100644 --- a/vault/external_tests/identity/groups_test.go +++ b/vault/external_tests/identity/groups_test.go @@ -179,7 +179,7 @@ func TestIdentityStore_ExternalGroupMembershipsAcrossMounts(t *testing.T) { } ldapMountAccessor1 := auths["ldap/"].Accessor - cleanup, cfg, _ := ldaphelper.PrepareTestContainer(t, "latest") + cleanup, cfg := ldaphelper.PrepareTestContainer(t, "latest") defer cleanup() // Configure LDAP auth @@ -281,7 +281,7 @@ func TestIdentityStore_ExternalGroupMembershipsAcrossMounts(t *testing.T) { t.Fatal(err) } - cleanup2, cfg2, _ := ldaphelper.PrepareTestContainer(t, "latest") + cleanup2, cfg2 := ldaphelper.PrepareTestContainer(t, "latest") defer cleanup2() // Configure LDAP auth diff --git a/vault/external_tests/identity/identity_test.go b/vault/external_tests/identity/identity_test.go index dec6fa422e69..f82f061cc69e 100644 --- a/vault/external_tests/identity/identity_test.go +++ b/vault/external_tests/identity/identity_test.go @@ -129,7 +129,7 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) { t.Fatalf("bad: group alias: %#v\n", aliasMap) } - cleanup, cfg, cfgtls := ldaphelper.PrepareTestContainer(t, "latest") + cleanup, cfg := ldaphelper.PrepareTestContainer(t, "latest") defer cleanup() // Configure LDAP auth @@ -223,7 +223,7 @@ func TestIdentityStore_Integ_GroupAliases(t *testing.T) { // 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(cfgtls) + conn, err := ldapClient.DialLDAP(cfg) if err != nil { t.Fatal(err) } diff --git a/vault/external_tests/token/token_test.go b/vault/external_tests/token/token_test.go index 70198d1376f8..7766095155b4 100644 --- a/vault/external_tests/token/token_test.go +++ b/vault/external_tests/token/token_test.go @@ -128,7 +128,7 @@ func TestTokenStore_IdentityPolicies(t *testing.T) { t.Fatal(err) } - cleanup, cfg, _ := ldap.PrepareTestContainer(t, "latest") + cleanup, cfg := ldap.PrepareTestContainer(t, "latest") defer cleanup() // Configure LDAP auth From 98edbb1c3483c9f818043b42dade8a0f83e544c9 Mon Sep 17 00:00:00 2001 From: Nick Cabatoff Date: Mon, 21 Oct 2019 14:52:01 -0400 Subject: [PATCH 6/8] Address review comments. --- builtin/credential/ldap/backend_test.go | 3 +-- helper/testhelpers/ldap/ldaphelper.go | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/builtin/credential/ldap/backend_test.go b/builtin/credential/ldap/backend_test.go index af6b653fe098..9caa0683b3e6 100644 --- a/builtin/credential/ldap/backend_test.go +++ b/builtin/credential/ldap/backend_test.go @@ -893,8 +893,7 @@ func TestLdapAuthBackend_ConfigUpgrade(t *testing.T) { "token_period": "5m", "token_explicit_max_ttl": "24h", }, - Storage: storage, - // TODO remove? + Storage: storage, Connection: &logical.Connection{}, } resp, err = b.HandleRequest(ctx, configReq) diff --git a/helper/testhelpers/ldap/ldaphelper.go b/helper/testhelpers/ldap/ldaphelper.go index c6dfb41b145a..5322684feac2 100644 --- a/helper/testhelpers/ldap/ldaphelper.go +++ b/helper/testhelpers/ldap/ldaphelper.go @@ -53,8 +53,10 @@ func PrepareTestContainer(t *testing.T, version string) (cleanup func(), cfg *ld } defer conn.Close() - _, err = client.GetUserBindDN(cfg, conn, "Philip J. Fry") - return err + 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) From b98c02afe8cb148fc77ff00ca84232000e992649 Mon Sep 17 00:00:00 2001 From: Nick Cabatoff Date: Tue, 22 Oct 2019 07:32:38 -0400 Subject: [PATCH 7/8] Update comment to explain how to query the docker LDAP server. --- builtin/credential/ldap/backend_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/builtin/credential/ldap/backend_test.go b/builtin/credential/ldap/backend_test.go index 9caa0683b3e6..3bc0b1d96c87 100644 --- a/builtin/credential/ldap/backend_test.go +++ b/builtin/credential/ldap/backend_test.go @@ -388,11 +388,10 @@ func TestLdapAuthBackend_UserPolicies(t *testing.T) { * which is a member of a group, `cn=admin_staff,ou=people,dc=example,dc=com` * * Querying the server from the command line: - * TODO - * $ 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 From f14d7f4b1a8ae80f71f0c267c9a93ae0878b15e1 Mon Sep 17 00:00:00 2001 From: Nick Cabatoff Date: Tue, 22 Oct 2019 11:24:12 -0400 Subject: [PATCH 8/8] Revert unnecessary change to prod code. --- sdk/helper/ldaputil/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/helper/ldaputil/client.go b/sdk/helper/ldaputil/client.go index c1425b729ade..dff8534d7a1c 100644 --- a/sdk/helper/ldaputil/client.go +++ b/sdk/helper/ldaputil/client.go @@ -127,7 +127,7 @@ func (c *Client) GetUserBindDN(cfg *ConfigEntry, conn Connection, username strin return bindDN, errwrap.Wrapf("LDAP search for binddn failed: {{err}}", err) } if len(result.Entries) != 1 { - return bindDN, fmt.Errorf("LDAP search for binddn 0 or not unique (%d results)", len(result.Entries)) + return bindDN, fmt.Errorf("LDAP search for binddn 0 or not unique") } bindDN = result.Entries[0].DN } else {