mirror of https://github.com/dexidp/dex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
829 lines
18 KiB
829 lines
18 KiB
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 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 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 |
|
}
|
|
|