ldap-upstream/internal/ldap/search_test.go
2026-11-01 22:17:59 -06:00

79 lines
2.7 KiB
Go

package ldap
import (
"errors"
"testing"
ldap "github.com/vjeantet/ldapserver"
)
// fakeConn stands in for the server's unexported client type so that
// per-connection bind state can be exercised in tests.
type fakeConn struct {
data interface{}
}
func (c *fakeConn) GetData() interface{} { return c.data }
func (c *fakeConn) SetData(d interface{}) { c.data = d }
func boundTestServer(c naClient) *server {
fc := &fakeConn{}
s := &server{l: testLogger(), c: c}
s.nc = []string{"dc=netauth", "dc=example", "dc=com"}
s.conn = func(*ldap.Message) connection { return fc }
return s
}
func TestSearchRequiresBind(t *testing.T) {
s := boundTestServer(&fakeClient{})
w := &recordingWriter{}
s.handleSearchEntities(w, mustDecode(t, berSearchRequest("ou=entities,dc=netauth,dc=example,dc=com")))
if len(w.responses) != 1 {
t.Fatalf("got %d responses, want exactly 1", len(w.responses))
}
if code := resultCode(t, w.responses[0]); code != ldap.LDAPResultInsufficientAccessRights {
t.Errorf("entities: result code is %d, want %d", code, ldap.LDAPResultInsufficientAccessRights)
}
w = &recordingWriter{}
s.handleSearchGroups(w, mustDecode(t, berSearchRequest("ou=groups,dc=netauth,dc=example,dc=com")))
if code := resultCode(t, w.responses[0]); code != ldap.LDAPResultInsufficientAccessRights {
t.Errorf("groups: result code is %d, want %d", code, ldap.LDAPResultInsufficientAccessRights)
}
}
func TestSearchAfterBindSucceeds(t *testing.T) {
s := boundTestServer(&fakeClient{})
// A successful bind marks the connection, so a follow-up search
// is no longer refused for lack of authentication.
s.handleBind(&recordingWriter{}, mustDecode(t,
berBindRequest("uid=jsmith,ou=entities,dc=netauth,dc=example,dc=com", "hunter2")))
w := &recordingWriter{}
s.handleSearchEntities(w, mustDecode(t, berSearchRequest("ou=entities,dc=netauth,dc=example,dc=com")))
if code := resultCode(t, w.responses[len(w.responses)-1]); code == ldap.LDAPResultInsufficientAccessRights {
t.Errorf("a bound connection was still refused")
}
}
func TestFailedRebindClearsConnection(t *testing.T) {
c := &fakeClient{authErr: errors.New("invalid password")}
s := boundTestServer(c)
// Mark the connection bound, then have a rebind fail; RFC 4511
// requires the connection to drop back to unauthenticated.
s.markBound(&ldap.Message{})
w := &recordingWriter{}
s.handleBind(w, mustDecode(t,
berBindRequest("uid=jsmith,ou=entities,dc=netauth,dc=example,dc=com", "wrong")))
if code := resultCode(t, w.responses[0]); code != ldap.LDAPResultInvalidCredentials {
t.Fatalf("bind result code is %d, want %d", code, ldap.LDAPResultInvalidCredentials)
}
if s.bound(&ldap.Message{}) {
t.Error("connection still marked bound after a failed bind")
}
}