From c43d537d5bb0eeb491153b00cdefcb54a6178187 Mon Sep 17 00:00:00 2001 From: ned Date: Sun, 23 Nov 2014 12:03:05 -0700 Subject: Implemented other LDAP server operations (add/delete/modify/extended/etc.) and tests. --- server_test.go | 376 +++++---------------------------------------------------- 1 file changed, 27 insertions(+), 349 deletions(-) (limited to 'server_test.go') diff --git a/server_test.go b/server_test.go index 9386a4a..7e813ec 100644 --- a/server_test.go +++ b/server_test.go @@ -61,7 +61,7 @@ func TestBindAnonFail(t *testing.T) { go func() { cmd := exec.Command("ldapsearch", "-H", ldapURL, "-x", "-b", "o=testers,c=test") out, _ := cmd.CombinedOutput() - if !strings.Contains(string(out), "ldap_bind: Inappropriate authentication (48)") { + if !strings.Contains(string(out), "ldap_bind: Invalid credentials (49)") { t.Errorf("ldapsearch failed: %v", string(out)) } done <- true @@ -186,7 +186,7 @@ func TestBindSSL(t *testing.T) { s := NewServer() s.QuitChannel(quit) s.BindFunc("", bindAnonOK{}) - if err := s.ListenAndServeTLS(listenString, "examples/cert_DONOTUSE.pem", "examples/key_DONOTUSE.pem"); err != nil { + if err := s.ListenAndServeTLS(listenString, "tests/cert_DONOTUSE.pem", "tests/key_DONOTUSE.pem"); err != nil { t.Errorf("s.ListenAndServeTLS failed: %s", err.Error()) } }() @@ -239,348 +239,6 @@ func TestBindPanic(t *testing.T) { quit <- true } -///////////////////////// -func TestSearchSimpleOK(t *testing.T) { - quit := make(chan bool) - done := make(chan bool) - go func() { - s := NewServer() - s.QuitChannel(quit) - s.SearchFunc("", searchSimple{}) - s.BindFunc("", bindSimple{}) - if err := s.ListenAndServe(listenString); err != nil { - t.Errorf("s.ListenAndServe failed: %s", err.Error()) - } - }() - - serverBaseDN := "o=testers,c=test" - - go func() { - cmd := exec.Command("ldapsearch", "-H", ldapURL, "-x", - "-b", serverBaseDN, "-D", "cn=testy,"+serverBaseDN, "-w", "iLike2test") - out, _ := cmd.CombinedOutput() - if !strings.Contains(string(out), "dn: cn=ned,o=testers,c=test") { - t.Errorf("ldapsearch failed: %v", string(out)) - } - if !strings.Contains(string(out), "uidNumber: 5000") { - t.Errorf("ldapsearch failed: %v", string(out)) - } - if !strings.Contains(string(out), "result: 0 Success") { - t.Errorf("ldapsearch failed: %v", string(out)) - } - if !strings.Contains(string(out), "numResponses: 4") { - t.Errorf("ldapsearch failed: %v", string(out)) - } - done <- true - }() - - select { - case <-done: - case <-time.After(timeout): - t.Errorf("ldapsearch command timed out") - } - quit <- true -} - -func TestSearchSizelimit(t *testing.T) { - quit := make(chan bool) - done := make(chan bool) - go func() { - s := NewServer() - s.EnforceLDAP = true - s.QuitChannel(quit) - s.SearchFunc("", searchSimple{}) - s.BindFunc("", bindSimple{}) - if err := s.ListenAndServe(listenString); err != nil { - t.Errorf("s.ListenAndServe failed: %s", err.Error()) - } - }() - - go func() { - cmd := exec.Command("ldapsearch", "-H", ldapURL, "-x", - "-b", serverBaseDN, "-D", "cn=testy,"+serverBaseDN, "-w", "iLike2test", "-z", "9") // effectively no limit for this test - out, _ := cmd.CombinedOutput() - if !strings.Contains(string(out), "result: 0 Success") { - t.Errorf("ldapsearch failed: %v", string(out)) - } - if !strings.Contains(string(out), "numEntries: 3") { - t.Errorf("ldapsearch sizelimit failed - not enough entries: %v", string(out)) - } - - cmd = exec.Command("ldapsearch", "-H", ldapURL, "-x", - "-b", serverBaseDN, "-D", "cn=testy,"+serverBaseDN, "-w", "iLike2test", "-z", "2") - out, _ = cmd.CombinedOutput() - if !strings.Contains(string(out), "result: 0 Success") { - t.Errorf("ldapsearch failed: %v", string(out)) - } - if !strings.Contains(string(out), "numEntries: 2") { - t.Errorf("ldapsearch sizelimit failed - too many entries: %v", string(out)) - } - done <- true - }() - - select { - case <-done: - case <-time.After(timeout): - t.Errorf("ldapsearch command timed out") - } - quit <- true -} - -///////////////////////// -func TestBindSearchMulti(t *testing.T) { - quit := make(chan bool) - done := make(chan bool) - go func() { - s := NewServer() - s.QuitChannel(quit) - s.BindFunc("", bindSimple{}) - s.BindFunc("c=testz", bindSimple2{}) - s.SearchFunc("", searchSimple{}) - s.SearchFunc("c=testz", searchSimple2{}) - if err := s.ListenAndServe(listenString); err != nil { - t.Errorf("s.ListenAndServe failed: %s", err.Error()) - } - }() - - go func() { - cmd := exec.Command("ldapsearch", "-H", ldapURL, "-x", "-b", "o=testers,c=test", - "-D", "cn=testy,o=testers,c=test", "-w", "iLike2test", "cn=ned") - out, _ := cmd.CombinedOutput() - if !strings.Contains(string(out), "result: 0 Success") { - t.Errorf("error routing default bind/search functions: %v", string(out)) - } - if !strings.Contains(string(out), "dn: cn=ned,o=testers,c=test") { - t.Errorf("search default routing failed: %v", string(out)) - } - cmd = exec.Command("ldapsearch", "-H", ldapURL, "-x", "-b", "o=testers,c=testz", - "-D", "cn=testy,o=testers,c=testz", "-w", "ZLike2test", "cn=hamburger") - out, _ = cmd.CombinedOutput() - if !strings.Contains(string(out), "result: 0 Success") { - t.Errorf("error routing custom bind/search functions: %v", string(out)) - } - if !strings.Contains(string(out), "dn: cn=hamburger,o=testers,c=testz") { - t.Errorf("search custom routing failed: %v", string(out)) - } - done <- true - }() - - select { - case <-done: - case <-time.After(timeout): - t.Errorf("ldapsearch command timed out") - } - - quit <- true -} - -///////////////////////// -func TestSearchPanic(t *testing.T) { - quit := make(chan bool) - done := make(chan bool) - go func() { - s := NewServer() - s.QuitChannel(quit) - s.SearchFunc("", searchPanic{}) - s.BindFunc("", bindAnonOK{}) - if err := s.ListenAndServe(listenString); err != nil { - t.Errorf("s.ListenAndServe failed: %s", err.Error()) - } - }() - - go func() { - cmd := exec.Command("ldapsearch", "-H", ldapURL, "-x", "-b", "o=testers,c=test") - out, _ := cmd.CombinedOutput() - if !strings.Contains(string(out), "result: 1 Operations error") { - t.Errorf("ldapsearch should have returned operations error due to panic: %v", string(out)) - } - done <- true - }() - - select { - case <-done: - case <-time.After(timeout): - t.Errorf("ldapsearch command timed out") - } - quit <- true -} - -///////////////////////// -type compileSearchFilterTest struct { - name string - filterStr string - numResponses string -} - -var searchFilterTestFilters = []compileSearchFilterTest{ - compileSearchFilterTest{name: "equalityOk", filterStr: "(uid=ned)", numResponses: "2"}, - compileSearchFilterTest{name: "equalityNo", filterStr: "(uid=foo)", numResponses: "1"}, - compileSearchFilterTest{name: "equalityOk", filterStr: "(objectclass=posixaccount)", numResponses: "4"}, - compileSearchFilterTest{name: "presentEmptyOk", filterStr: "", numResponses: "4"}, - compileSearchFilterTest{name: "presentOk", filterStr: "(objectclass=*)", numResponses: "4"}, - compileSearchFilterTest{name: "presentOk", filterStr: "(description=*)", numResponses: "3"}, - compileSearchFilterTest{name: "presentNo", filterStr: "(foo=*)", numResponses: "1"}, - compileSearchFilterTest{name: "andOk", filterStr: "(&(uid=ned)(objectclass=posixaccount))", numResponses: "2"}, - compileSearchFilterTest{name: "andNo", filterStr: "(&(uid=ned)(objectclass=posixgroup))", numResponses: "1"}, - compileSearchFilterTest{name: "andNo", filterStr: "(&(uid=ned)(uid=trent))", numResponses: "1"}, - compileSearchFilterTest{name: "orOk", filterStr: "(|(uid=ned)(uid=trent))", numResponses: "3"}, - compileSearchFilterTest{name: "orOk", filterStr: "(|(uid=ned)(objectclass=posixaccount))", numResponses: "4"}, - compileSearchFilterTest{name: "orNo", filterStr: "(|(uid=foo)(objectclass=foo))", numResponses: "1"}, - compileSearchFilterTest{name: "andOrOk", filterStr: "(&(|(uid=ned)(uid=trent))(objectclass=posixaccount))", numResponses: "3"}, - compileSearchFilterTest{name: "notOk", filterStr: "(!(uid=ned))", numResponses: "3"}, - compileSearchFilterTest{name: "notOk", filterStr: "(!(uid=foo))", numResponses: "4"}, - compileSearchFilterTest{name: "notAndOrOk", filterStr: "(&(|(uid=ned)(uid=trent))(!(objectclass=posixgroup)))", numResponses: "3"}, - /* - compileSearchFilterTest{filterStr: "(sn=Mill*)", filterType: FilterSubstrings}, - compileSearchFilterTest{filterStr: "(sn=*Mill)", filterType: FilterSubstrings}, - compileSearchFilterTest{filterStr: "(sn=*Mill*)", filterType: FilterSubstrings}, - compileSearchFilterTest{filterStr: "(sn>=Miller)", filterType: FilterGreaterOrEqual}, - compileSearchFilterTest{filterStr: "(sn<=Miller)", filterType: FilterLessOrEqual}, - compileSearchFilterTest{filterStr: "(sn~=Miller)", filterType: FilterApproxMatch}, - */ -} - -///////////////////////// -func TestSearchFiltering(t *testing.T) { - quit := make(chan bool) - done := make(chan bool) - go func() { - s := NewServer() - s.EnforceLDAP = true - s.QuitChannel(quit) - s.SearchFunc("", searchSimple{}) - s.BindFunc("", bindSimple{}) - if err := s.ListenAndServe(listenString); err != nil { - t.Errorf("s.ListenAndServe failed: %s", err.Error()) - } - }() - - for _, i := range searchFilterTestFilters { - t.Log(i.name) - - go func() { - cmd := exec.Command("ldapsearch", "-H", ldapURL, "-x", - "-b", serverBaseDN, "-D", "cn=testy,"+serverBaseDN, "-w", "iLike2test", i.filterStr) - out, _ := cmd.CombinedOutput() - if !strings.Contains(string(out), "numResponses: "+i.numResponses) { - t.Errorf("ldapsearch failed - expected numResponses==%d: %v", i.numResponses, string(out)) - } - done <- true - }() - - select { - case <-done: - case <-time.After(timeout): - t.Errorf("ldapsearch command timed out") - } - } - quit <- true -} - -///////////////////////// -func TestSearchAttributes(t *testing.T) { - quit := make(chan bool) - done := make(chan bool) - go func() { - s := NewServer() - s.EnforceLDAP = true - s.QuitChannel(quit) - s.SearchFunc("", searchSimple{}) - s.BindFunc("", bindSimple{}) - if err := s.ListenAndServe(listenString); err != nil { - t.Errorf("s.ListenAndServe failed: %s", err.Error()) - } - }() - - go func() { - filterString := "" - cmd := exec.Command("ldapsearch", "-H", ldapURL, "-x", - "-b", serverBaseDN, "-D", "cn=testy,"+serverBaseDN, "-w", "iLike2test", filterString, "cn") - out, _ := cmd.CombinedOutput() - - if !strings.Contains(string(out), "dn: cn=ned,o=testers,c=test") { - t.Errorf("ldapsearch failed - missing requested DN attribute: %v", string(out)) - } - if !strings.Contains(string(out), "cn: ned") { - t.Errorf("ldapsearch failed - missing requested CN attribute: %v", string(out)) - } - if strings.Contains(string(out), "uidNumber") { - t.Errorf("ldapsearch failed - uidNumber attr should not be displayed: %v", string(out)) - } - if strings.Contains(string(out), "accountstatus") { - t.Errorf("ldapsearch failed - accountstatus attr should not be displayed: %v", string(out)) - } - done <- true - }() - - select { - case <-done: - case <-time.After(timeout): - t.Errorf("ldapsearch command timed out") - } - quit <- true -} - -///////////////////////// -func TestSearchScope(t *testing.T) { - quit := make(chan bool) - done := make(chan bool) - go func() { - s := NewServer() - s.EnforceLDAP = true - s.QuitChannel(quit) - s.SearchFunc("", searchSimple{}) - s.BindFunc("", bindSimple{}) - if err := s.ListenAndServe(listenString); err != nil { - t.Errorf("s.ListenAndServe failed: %s", err.Error()) - } - }() - - go func() { - cmd := exec.Command("ldapsearch", "-H", ldapURL, "-x", - "-b", "c=test", "-D", "cn=testy,o=testers,c=test", "-w", "iLike2test", "-s", "sub", "cn=trent") - out, _ := cmd.CombinedOutput() - if !strings.Contains(string(out), "dn: cn=trent,o=testers,c=test") { - t.Errorf("ldapsearch 'sub' scope failed - didn't find expected DN: %v", string(out)) - } - - cmd = exec.Command("ldapsearch", "-H", ldapURL, "-x", - "-b", "o=testers,c=test", "-D", "cn=testy,o=testers,c=test", "-w", "iLike2test", "-s", "one", "cn=trent") - out, _ = cmd.CombinedOutput() - if !strings.Contains(string(out), "dn: cn=trent,o=testers,c=test") { - t.Errorf("ldapsearch 'one' scope failed - didn't find expected DN: %v", string(out)) - } - cmd = exec.Command("ldapsearch", "-H", ldapURL, "-x", - "-b", "c=test", "-D", "cn=testy,o=testers,c=test", "-w", "iLike2test", "-s", "one", "cn=trent") - out, _ = cmd.CombinedOutput() - if strings.Contains(string(out), "dn: cn=trent,o=testers,c=test") { - t.Errorf("ldapsearch 'one' scope failed - found unexpected DN: %v", string(out)) - } - - cmd = exec.Command("ldapsearch", "-H", ldapURL, "-x", - "-b", "cn=trent,o=testers,c=test", "-D", "cn=testy,o=testers,c=test", "-w", "iLike2test", "-s", "base", "cn=trent") - out, _ = cmd.CombinedOutput() - if !strings.Contains(string(out), "dn: cn=trent,o=testers,c=test") { - t.Errorf("ldapsearch 'base' scope failed - didn't find expected DN: %v", string(out)) - } - cmd = exec.Command("ldapsearch", "-H", ldapURL, "-x", - "-b", "o=testers,c=test", "-D", "cn=testy,o=testers,c=test", "-w", "iLike2test", "-s", "base", "cn=trent") - out, _ = cmd.CombinedOutput() - if strings.Contains(string(out), "dn: cn=trent,o=testers,c=test") { - t.Errorf("ldapsearch 'base' scope failed - found unexpected DN: %v", string(out)) - } - - done <- true - }() - - select { - case <-done: - case <-time.After(timeout): - t.Errorf("ldapsearch command timed out") - } - quit <- true -} - ///////////////////////// type testStatsWriter struct { buffer *bytes.Buffer @@ -625,7 +283,8 @@ func TestSearchStats(t *testing.T) { } stats := s.GetStats() - if stats.Conns != 1 || stats.Binds != 1 { + log.Println(stats) + if stats.Conns != 2 || stats.Binds != 1 { t.Errorf("Stats data missing or incorrect: %v", w.buffer.String()) } quit <- true @@ -635,7 +294,7 @@ func TestSearchStats(t *testing.T) { type bindAnonOK struct { } -func (b bindAnonOK) Bind(bindDN, bindSimplePw string, conn net.Conn) (uint64, error) { +func (b bindAnonOK) Bind(bindDN, bindSimplePw string, conn net.Conn) (LDAPResultCode, error) { if bindDN == "" && bindSimplePw == "" { return LDAPResultSuccess, nil } @@ -645,7 +304,7 @@ func (b bindAnonOK) Bind(bindDN, bindSimplePw string, conn net.Conn) (uint64, er type bindSimple struct { } -func (b bindSimple) Bind(bindDN, bindSimplePw string, conn net.Conn) (uint64, error) { +func (b bindSimple) Bind(bindDN, bindSimplePw string, conn net.Conn) (LDAPResultCode, error) { if bindDN == "cn=testy,o=testers,c=test" && bindSimplePw == "iLike2test" { return LDAPResultSuccess, nil } @@ -655,7 +314,7 @@ func (b bindSimple) Bind(bindDN, bindSimplePw string, conn net.Conn) (uint64, er type bindSimple2 struct { } -func (b bindSimple2) Bind(bindDN, bindSimplePw string, conn net.Conn) (uint64, error) { +func (b bindSimple2) Bind(bindDN, bindSimplePw string, conn net.Conn) (LDAPResultCode, error) { if bindDN == "cn=testy,o=testers,c=testz" && bindSimplePw == "ZLike2test" { return LDAPResultSuccess, nil } @@ -665,7 +324,7 @@ func (b bindSimple2) Bind(bindDN, bindSimplePw string, conn net.Conn) (uint64, e type bindPanic struct { } -func (b bindPanic) Bind(bindDN, bindSimplePw string, conn net.Conn) (uint64, error) { +func (b bindPanic) Bind(bindDN, bindSimplePw string, conn net.Conn) (LDAPResultCode, error) { panic("test panic at the disco") return LDAPResultInvalidCredentials, nil } @@ -730,3 +389,22 @@ func (s searchPanic) Search(boundDN string, searchReq SearchRequest, conn net.Co panic("this is a test panic") return ServerSearchResult{entries, []string{}, []Control{}, LDAPResultSuccess}, nil } + +type searchControls struct { +} + +func (s searchControls) Search(boundDN string, searchReq SearchRequest, conn net.Conn) (ServerSearchResult, error) { + entries := []*Entry{} + if len(searchReq.Controls) == 1 && searchReq.Controls[0].GetControlType() == "1.2.3.4.5" { + newEntry := &Entry{"cn=hamburger,o=testers,c=testz", []*EntryAttribute{ + &EntryAttribute{"cn", []string{"hamburger"}}, + &EntryAttribute{"o", []string{"testers"}}, + &EntryAttribute{"uidNumber", []string{"5000"}}, + &EntryAttribute{"accountstatus", []string{"active"}}, + &EntryAttribute{"uid", []string{"hamburger"}}, + &EntryAttribute{"objectclass", []string{"posixaccount"}}, + }} + entries = append(entries, newEntry) + } + return ServerSearchResult{entries, []string{}, []Control{}, LDAPResultSuccess}, nil +} -- cgit v1.2.3