dex/connector/ldap/ldap_test.go
Stephan Renatus df18cb0c22
ldap_test: add filter tests
The filters for user and group searches hadn't been included in our LDAP
tests. Now they are.

The concrete test cases are somewhat contrived, but that shouldn't
matter too much. Also note that the example queries I've used are not
supported in AD: https://stackoverflow.com/a/10043452

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-02-03 11:06:11 +01:00

1032 lines
23 KiB
Go

package ldap
import (
"bytes"
"context"
"io/ioutil"
"net/url"
"os"
"os/exec"
"path/filepath"
"sync"
"testing"
"text/template"
"time"
"github.com/kylelemons/godebug/pretty"
"github.com/sirupsen/logrus"
"github.com/dexidp/dex/connector"
)
const envVar = "DEX_LDAP_TESTS"
// connectionMethod indicates how the test should connect to the LDAP server.
type connectionMethod int32
const (
connectStartTLS connectionMethod = iota
connectLDAPS
connectLDAP
connectInsecureSkipVerify
)
// subtest is a login test against a given schema.
type subtest struct {
// Name of the sub-test.
name string
// Password credentials, and if the connector should request
// groups as well.
username string
password string
groups bool
// Expected result of the login.
wantErr bool
wantBadPW bool
want connector.Identity
}
func TestQuery(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
},
},
{
name: "validpassword2",
username: "john",
password: "bar",
want: connector.Identity{
UserID: "cn=john,ou=People,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
},
},
{
name: "invalidpassword",
username: "jane",
password: "badpassword",
wantBadPW: true,
},
{
name: "invaliduser",
username: "idontexist",
password: "foo",
wantBadPW: true, // Want invalid password, not a query error.
},
}
runTests(t, schema, connectLDAP, c, tests)
}
func TestQueryWithEmailSuffix(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
userpassword: bar
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailSuffix = "test.example.com"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
tests := []subtest{
{
name: "ignoremailattr",
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
Username: "jane",
Email: "jane@test.example.com",
EmailVerified: true,
},
},
{
name: "nomailattr",
username: "john",
password: "bar",
want: connector.Identity{
UserID: "cn=john,ou=People,dc=example,dc=org",
Username: "john",
Email: "john@test.example.com",
EmailVerified: true,
},
},
}
runTests(t, schema, connectLDAP, c, tests)
}
func TestUserFilter(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=Seattle,dc=example,dc=org
objectClass: organizationalUnit
ou: Seattle
dn: ou=Portland,dc=example,dc=org
objectClass: organizationalUnit
ou: Portland
dn: ou=People,ou=Seattle,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: ou=People,ou=Portland,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,ou=Seattle,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=jane,ou=People,ou=Portland,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoefromportland@example.com
userpassword: baz
dn: cn=john,ou=People,ou=Seattle,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
`
c := &Config{}
c.UserSearch.BaseDN = "dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
c.UserSearch.Filter = "(ou:dn:=Seattle)"
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,ou=Seattle,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
},
},
{
name: "validpassword2",
username: "john",
password: "bar",
want: connector.Identity{
UserID: "cn=john,ou=People,ou=Seattle,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
},
},
{
name: "invalidpassword",
username: "jane",
password: "badpassword",
wantBadPW: true,
},
{
name: "invaliduser",
username: "idontexist",
password: "foo",
wantBadPW: true, // Want invalid password, not a query error.
},
}
runTests(t, schema, connectLDAP, c, tests)
}
func TestGroupQuery(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
# Group definitions.
dn: ou=Groups,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: cn=admins,ou=Groups,dc=example,dc=org
objectClass: groupOfNames
cn: admins
member: cn=john,ou=People,dc=example,dc=org
member: cn=jane,ou=People,dc=example,dc=org
dn: cn=developers,ou=Groups,dc=example,dc=org
objectClass: groupOfNames
cn: developers
member: cn=jane,ou=People,dc=example,dc=org
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
c.GroupSearch.BaseDN = "ou=Groups,dc=example,dc=org"
c.GroupSearch.UserAttr = "DN"
c.GroupSearch.GroupAttr = "member"
c.GroupSearch.NameAttr = "cn"
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
groups: true,
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
Groups: []string{"admins", "developers"},
},
},
{
name: "validpassword2",
username: "john",
password: "bar",
groups: true,
want: connector.Identity{
UserID: "cn=john,ou=People,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
Groups: []string{"admins"},
},
},
}
runTests(t, schema, connectLDAP, c, tests)
}
func TestGroupsOnUserEntity(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
# Groups are enumerated as part of the user entity instead of the members being
# a list on the group entity.
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
departmentNumber: 1000
departmentNumber: 1001
dn: cn=john,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
departmentNumber: 1000
departmentNumber: 1002
# Group definitions. Notice that they don't have any "member" field.
dn: ou=Groups,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: cn=admins,ou=Groups,dc=example,dc=org
objectClass: posixGroup
cn: admins
gidNumber: 1000
dn: cn=developers,ou=Groups,dc=example,dc=org
objectClass: posixGroup
cn: developers
gidNumber: 1001
dn: cn=designers,ou=Groups,dc=example,dc=org
objectClass: posixGroup
cn: designers
gidNumber: 1002
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
c.GroupSearch.BaseDN = "ou=Groups,dc=example,dc=org"
c.GroupSearch.UserAttr = "departmentNumber"
c.GroupSearch.GroupAttr = "gidNumber"
c.GroupSearch.NameAttr = "cn"
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
groups: true,
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
Groups: []string{"admins", "developers"},
},
},
{
name: "validpassword2",
username: "john",
password: "bar",
groups: true,
want: connector.Identity{
UserID: "cn=john,ou=People,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
Groups: []string{"admins", "designers"},
},
},
}
runTests(t, schema, connectLDAP, c, tests)
}
func TestGroupFilter(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
# Group definitions.
dn: ou=Seattle,dc=example,dc=org
objectClass: organizationalUnit
ou: Seattle
dn: ou=Portland,dc=example,dc=org
objectClass: organizationalUnit
ou: Portland
dn: ou=Groups,ou=Seattle,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: ou=Groups,ou=Portland,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: cn=qa,ou=Groups,ou=Portland,dc=example,dc=org
objectClass: groupOfNames
cn: qa
member: cn=john,ou=People,dc=example,dc=org
dn: cn=admins,ou=Groups,ou=Seattle,dc=example,dc=org
objectClass: groupOfNames
cn: admins
member: cn=john,ou=People,dc=example,dc=org
member: cn=jane,ou=People,dc=example,dc=org
dn: cn=developers,ou=Groups,ou=Seattle,dc=example,dc=org
objectClass: groupOfNames
cn: developers
member: cn=jane,ou=People,dc=example,dc=org
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
c.GroupSearch.BaseDN = "dc=example,dc=org"
c.GroupSearch.UserAttr = "DN"
c.GroupSearch.GroupAttr = "member"
c.GroupSearch.NameAttr = "cn"
c.GroupSearch.Filter = "(ou:dn:=Seattle)" // ignore other groups
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
groups: true,
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
Groups: []string{"admins", "developers"},
},
},
{
name: "validpassword2",
username: "john",
password: "bar",
groups: true,
want: connector.Identity{
UserID: "cn=john,ou=People,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
Groups: []string{"admins"},
},
},
}
runTests(t, schema, connectLDAP, c, tests)
}
func TestStartTLS(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
},
},
}
runTests(t, schema, connectStartTLS, c, tests)
}
func TestInsecureSkipVerify(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
},
},
}
runTests(t, schema, connectInsecureSkipVerify, c, tests)
}
func TestLDAPS(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
},
},
}
runTests(t, schema, connectLDAPS, c, tests)
}
func TestUsernamePrompt(t *testing.T) {
tests := map[string]struct {
config Config
expected string
}{
"with usernamePrompt unset it returns \"\"": {
config: Config{},
expected: "",
},
"with usernamePrompt set it returns that": {
config: Config{UsernamePrompt: "Email address"},
expected: "Email address",
},
}
for n, d := range tests {
t.Run(n, func(t *testing.T) {
conn := &ldapConnector{Config: d.config}
if actual := conn.Prompt(); actual != d.expected {
t.Errorf("expected %v, got %v", d.expected, actual)
}
})
}
}
// runTests runs a set of tests against an LDAP schema. It does this by
// setting up an OpenLDAP server and injecting the provided scheme.
//
// The tests require the slapd and ldapadd binaries available in the host
// machine's PATH.
//
// The DEX_LDAP_TESTS must be set to "1"
func runTests(t *testing.T, schema string, connMethod connectionMethod, config *Config, tests []subtest) {
if os.Getenv(envVar) != "1" {
t.Skipf("%s not set. Skipping test (run 'export %s=1' to run tests)", envVar, envVar)
}
for _, cmd := range []string{"slapd", "ldapadd"} {
if _, err := exec.LookPath(cmd); err != nil {
t.Errorf("%s not available", cmd)
}
}
wd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
tempDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)
configBytes := new(bytes.Buffer)
data := tmplData{
TempDir: tempDir,
Includes: includes(t, wd),
}
data.TLSCertPath, data.TLSKeyPath = tlsAssets(t, wd)
if err := slapdConfigTmpl.Execute(configBytes, data); err != nil {
t.Fatal(err)
}
configPath := filepath.Join(tempDir, "ldap.conf")
if err := ioutil.WriteFile(configPath, configBytes.Bytes(), 0644); err != nil {
t.Fatal(err)
}
schemaPath := filepath.Join(tempDir, "schema.ldap")
if err := ioutil.WriteFile(schemaPath, []byte(schema), 0644); err != nil {
t.Fatal(err)
}
socketPath := url.QueryEscape(filepath.Join(tempDir, "ldap.unix"))
slapdOut := new(bytes.Buffer)
cmd := exec.Command(
"slapd",
"-d", "any",
"-h", "ldap://localhost:10389/ ldaps://localhost:10636/ ldapi://"+socketPath,
"-f", configPath,
)
cmd.Stdout = slapdOut
cmd.Stderr = slapdOut
if err := cmd.Start(); err != nil {
t.Fatal(err)
}
var (
// Wait group finishes once slapd has exited.
//
// Use a wait group because multiple goroutines can't listen on
// cmd.Wait(). It triggers the race detector.
wg = new(sync.WaitGroup)
// Ensure only one condition can set the slapdFailed boolean.
once = new(sync.Once)
slapdFailed bool
)
wg.Add(1)
go func() { cmd.Wait(); wg.Done() }()
defer func() {
if slapdFailed {
// If slapd exited before it was killed, print its logs.
t.Logf("%s\n", slapdOut)
}
}()
go func() {
wg.Wait()
once.Do(func() { slapdFailed = true })
}()
defer func() {
once.Do(func() { slapdFailed = false })
cmd.Process.Kill()
wg.Wait()
}()
// Try a few times to connect to the LDAP server. On slower machines
// it can take a while for it to come up.
connected := false
wait := 100 * time.Millisecond
for i := 0; i < 5; i++ {
time.Sleep(wait)
ldapadd := exec.Command(
"ldapadd", "-x",
"-D", "cn=admin,dc=example,dc=org",
"-w", "admin",
"-f", schemaPath,
"-H", "ldap://localhost:10389/",
)
if out, err := ldapadd.CombinedOutput(); err != nil {
t.Logf("ldapadd: %s", out)
wait = wait * 2 // backoff
continue
}
connected = true
break
}
if !connected {
t.Errorf("ldapadd command failed")
return
}
// Shallow copy.
c := *config
// We need to configure host parameters but don't want to overwrite user or
// group search configuration.
switch connMethod {
case connectStartTLS:
c.Host = "localhost:10389"
c.RootCA = "testdata/ca.crt"
c.StartTLS = true
case connectLDAPS:
c.Host = "localhost:10636"
c.RootCA = "testdata/ca.crt"
case connectInsecureSkipVerify:
c.Host = "localhost:10636"
c.InsecureSkipVerify = true
case connectLDAP:
c.Host = "localhost:10389"
c.InsecureNoSSL = true
}
c.BindDN = "cn=admin,dc=example,dc=org"
c.BindPW = "admin"
l := &logrus.Logger{Out: ioutil.Discard, Formatter: &logrus.TextFormatter{}}
conn, err := c.openConnector(l)
if err != nil {
t.Errorf("open connector: %v", err)
}
for _, test := range tests {
if test.name == "" {
t.Fatal("go a subtest with no name")
}
// Run the subtest.
t.Run(test.name, func(t *testing.T) {
s := connector.Scopes{OfflineAccess: true, Groups: test.groups}
ident, validPW, err := conn.Login(context.Background(), s, test.username, test.password)
if err != nil {
if !test.wantErr {
t.Fatalf("query failed: %v", err)
}
return
}
if test.wantErr {
t.Fatalf("wanted query to fail")
}
if !validPW {
if !test.wantBadPW {
t.Fatalf("invalid password: %v", err)
}
return
}
if test.wantBadPW {
t.Fatalf("wanted invalid password")
}
got := ident
got.ConnectorData = nil
if diff := pretty.Compare(test.want, got); diff != "" {
t.Error(diff)
return
}
// Verify that refresh tokens work.
ident, err = conn.Refresh(context.Background(), s, ident)
if err != nil {
t.Errorf("refresh failed: %v", err)
}
got = ident
got.ConnectorData = nil
if diff := pretty.Compare(test.want, got); diff != "" {
t.Errorf("after refresh: %s", diff)
}
})
}
}
// Standard OpenLDAP schema files to include.
//
// These are copied from the /etc/openldap/schema directory.
var includeFiles = []string{
"core.schema",
"cosine.schema",
"inetorgperson.schema",
"misc.schema",
"nis.schema",
"openldap.schema",
}
// tmplData is the struct used to execute the SLAPD config template.
type tmplData struct {
// Directory for database to be writen to.
TempDir string
// List of schema files to include.
Includes []string
// TLS assets for LDAPS.
TLSKeyPath string
TLSCertPath string
}
// Config template copied from:
// http://www.zytrax.com/books/ldap/ch5/index.html#step1-slapd
//
// TLS instructions found here:
// http://www.openldap.org/doc/admin24/tls.html
var slapdConfigTmpl = template.Must(template.New("").Parse(`
{{ range $i, $include := .Includes }}
include {{ $include }}
{{ end }}
# MODULELOAD definitions
# not required (comment out) before version 2.3
moduleload back_bdb.la
database bdb
suffix "dc=example,dc=org"
# root or superuser
rootdn "cn=admin,dc=example,dc=org"
rootpw admin
# The database directory MUST exist prior to running slapd AND
# change path as necessary
directory {{ .TempDir }}
TLSCertificateFile {{ .TLSCertPath }}
TLSCertificateKeyFile {{ .TLSKeyPath }}
# Indices to maintain for this directory
# unique id so equality match only
index uid eq
# allows general searching on commonname, givenname and email
index cn,gn,mail eq,sub
# allows multiple variants on surname searching
index sn eq,sub
# sub above includes subintial,subany,subfinal
# optimise department searches
index ou eq
# if searches will include objectClass uncomment following
# index objectClass eq
# shows use of default index parameter
index default eq,sub
# indices missing - uses default eq,sub
index telephonenumber
# other database parameters
# read more in slapd.conf reference section
cachesize 10000
checkpoint 128 15
`))
func tlsAssets(t *testing.T, wd string) (certPath, keyPath string) {
certPath = filepath.Join(wd, "testdata", "server.crt")
keyPath = filepath.Join(wd, "testdata", "server.key")
for _, p := range []string{certPath, keyPath} {
if _, err := os.Stat(p); err != nil {
t.Fatalf("failed to find TLS asset file: %s %v", p, err)
}
}
return
}
func includes(t *testing.T, wd string) (paths []string) {
for _, f := range includeFiles {
p := filepath.Join(wd, "testdata", f)
if _, err := os.Stat(p); err != nil {
t.Fatalf("failed to find schema file: %s %v", p, err)
}
paths = append(paths, p)
}
return
}