package openldap import ( "path/filepath" "strconv" "testing" "github.com/docker/go-connections/nat" "github.com/go-ldap/ldap/v3" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go/wait" "github.com/influxdata/telegraf/testutil" ) const ( servicePort = "1389" servicePortSecure = "1636" ) func TestOpenldapMockResult(t *testing.T) { var acc testutil.Accumulator mockSearchResult := ldap.SearchResult{ Entries: []*ldap.Entry{ { DN: "cn=Total,cn=Connections,cn=Monitor", Attributes: []*ldap.EntryAttribute{{Name: "monitorCounter", Values: []string{"1"}}}, }, }, } o := &Openldap{ Host: "localhost", Port: 389, } gatherSearchResult(&mockSearchResult, o, &acc) commonTests(t, o, &acc) } func TestOpenldapNoConnectionIntegration(t *testing.T) { if testing.Short() { t.Skip("Skipping integration test in short mode") } o := &Openldap{ Host: "nosuchhost", Port: 389, } var acc testutil.Accumulator err := o.Gather(&acc) require.NoError(t, err) // test that we didn't return an error require.Zero(t, acc.NFields()) // test that we didn't return any fields require.NotEmpty(t, acc.Errors) // test that we set an error } func TestOpenldapGeneratesMetricsIntegration(t *testing.T) { if testing.Short() { t.Skip("Skipping integration test in short mode") } container := testutil.Container{ Image: "bitnami/openldap", ExposedPorts: []string{servicePort}, Env: map[string]string{ "LDAP_ADMIN_USERNAME": "manager", "LDAP_ADMIN_PASSWORD": "secret", }, WaitingFor: wait.ForAll( wait.ForLog("slapd starting"), wait.ForListeningPort(nat.Port(servicePort)), ), } err := container.Start() require.NoError(t, err, "failed to start container") defer container.Terminate() port, err := strconv.Atoi(container.Ports[servicePort]) require.NoError(t, err) o := &Openldap{ Host: container.Address, Port: port, BindDn: "CN=manager,DC=example,DC=org", BindPassword: "secret", } var acc testutil.Accumulator err = o.Gather(&acc) require.NoError(t, err) commonTests(t, o, &acc) } func TestOpenldapStartTLSIntegration(t *testing.T) { if testing.Short() { t.Skip("Skipping integration test in short mode") } pki := testutil.NewPKI("../../../testutil/pki") tlsPem, err := filepath.Abs(pki.ServerCertAndKeyPath()) require.NoError(t, err) tlsCert, err := filepath.Abs(pki.ServerCertPath()) require.NoError(t, err) tlsKey, err := filepath.Abs(pki.ServerKeyPath()) require.NoError(t, err) container := testutil.Container{ Image: "bitnami/openldap", ExposedPorts: []string{servicePort}, Env: map[string]string{ "LDAP_ADMIN_USERNAME": "manager", "LDAP_ADMIN_PASSWORD": "secret", "LDAP_ENABLE_TLS": "yes", "LDAP_TLS_CA_FILE": "server.pem", "LDAP_TLS_CERT_FILE": "server.crt", "LDAP_TLS_KEY_FILE": "server.key", }, Files: map[string]string{ "/server.pem": tlsPem, "/server.crt": tlsCert, "/server.key": tlsKey, }, WaitingFor: wait.ForAll( wait.ForLog("slapd starting"), wait.ForListeningPort(nat.Port(servicePort)), ), } err = container.Start() require.NoError(t, err, "failed to start container") defer container.Terminate() port, err := strconv.Atoi(container.Ports[servicePort]) require.NoError(t, err) cert, err := filepath.Abs(pki.ClientCertPath()) require.NoError(t, err) o := &Openldap{ Host: container.Address, Port: port, SSL: "starttls", InsecureSkipVerify: true, BindDn: "CN=manager,DC=example,DC=org", BindPassword: "secret", TLSCA: cert, } var acc testutil.Accumulator err = o.Gather(&acc) require.NoError(t, err) commonTests(t, o, &acc) } func TestOpenldapLDAPSIntegration(t *testing.T) { if testing.Short() { t.Skip("Skipping integration test in short mode") } pki := testutil.NewPKI("../../../testutil/pki") tlsPem, err := filepath.Abs(pki.ServerCertAndKeyPath()) require.NoError(t, err) tlsCert, err := filepath.Abs(pki.ServerCertPath()) require.NoError(t, err) tlsKey, err := filepath.Abs(pki.ServerKeyPath()) require.NoError(t, err) container := testutil.Container{ Image: "bitnami/openldap", ExposedPorts: []string{servicePortSecure}, Env: map[string]string{ "LDAP_ADMIN_USERNAME": "manager", "LDAP_ADMIN_PASSWORD": "secret", "LDAP_ENABLE_TLS": "yes", "LDAP_TLS_CA_FILE": "server.pem", "LDAP_TLS_CERT_FILE": "server.crt", "LDAP_TLS_KEY_FILE": "server.key", }, Files: map[string]string{ "/server.pem": tlsPem, "/server.crt": tlsCert, "/server.key": tlsKey, }, WaitingFor: wait.ForAll( wait.ForLog("slapd starting"), wait.ForListeningPort(nat.Port(servicePortSecure)), ), } err = container.Start() require.NoError(t, err, "failed to start container") defer container.Terminate() port, err := strconv.Atoi(container.Ports[servicePortSecure]) require.NoError(t, err) o := &Openldap{ Host: container.Address, Port: port, SSL: "ldaps", InsecureSkipVerify: true, BindDn: "CN=manager,DC=example,DC=org", BindPassword: "secret", } var acc testutil.Accumulator err = o.Gather(&acc) require.NoError(t, err) commonTests(t, o, &acc) } func TestOpenldapInvalidSSLIntegration(t *testing.T) { if testing.Short() { t.Skip("Skipping integration test in short mode") } pki := testutil.NewPKI("../../../testutil/pki") tlsPem, err := filepath.Abs(pki.ServerCertAndKeyPath()) require.NoError(t, err) tlsCert, err := filepath.Abs(pki.ServerCertPath()) require.NoError(t, err) tlsKey, err := filepath.Abs(pki.ServerKeyPath()) require.NoError(t, err) container := testutil.Container{ Image: "bitnami/openldap", ExposedPorts: []string{servicePortSecure}, Env: map[string]string{ "LDAP_ADMIN_USERNAME": "manager", "LDAP_ADMIN_PASSWORD": "secret", "LDAP_ENABLE_TLS": "yes", "LDAP_TLS_CA_FILE": "server.pem", "LDAP_TLS_CERT_FILE": "server.crt", "LDAP_TLS_KEY_FILE": "server.key", }, Files: map[string]string{ "/server.pem": tlsPem, "/server.crt": tlsCert, "/server.key": tlsKey, }, WaitingFor: wait.ForAll( wait.ForLog("slapd starting"), wait.ForListeningPort(nat.Port(servicePortSecure)), ), } err = container.Start() require.NoError(t, err, "failed to start container") defer container.Terminate() port, err := strconv.Atoi(container.Ports[servicePortSecure]) require.NoError(t, err) o := &Openldap{ Host: container.Address, Port: port, SSL: "invalid", InsecureSkipVerify: true, } var acc testutil.Accumulator err = o.Gather(&acc) require.NoError(t, err) // test that we didn't return an error require.Zero(t, acc.NFields()) // test that we didn't return any fields require.NotEmpty(t, acc.Errors) // test that we set an error } func TestOpenldapBindIntegration(t *testing.T) { if testing.Short() { t.Skip("Skipping integration test in short mode") } container := testutil.Container{ Image: "bitnami/openldap", ExposedPorts: []string{servicePort}, Env: map[string]string{ "LDAP_ADMIN_USERNAME": "manager", "LDAP_ADMIN_PASSWORD": "secret", }, WaitingFor: wait.ForAll( wait.ForLog("slapd starting"), wait.ForListeningPort(nat.Port(servicePort)), ), } err := container.Start() require.NoError(t, err, "failed to start container") defer container.Terminate() port, err := strconv.Atoi(container.Ports[servicePort]) require.NoError(t, err) o := &Openldap{ Host: container.Address, Port: port, SSL: "", InsecureSkipVerify: true, BindDn: "CN=manager,DC=example,DC=org", BindPassword: "secret", } var acc testutil.Accumulator err = o.Gather(&acc) require.NoError(t, err) commonTests(t, o, &acc) } func commonTests(t *testing.T, o *Openldap, acc *testutil.Accumulator) { // helpful local commands to run: // ldapwhoami -D "CN=manager,DC=example,DC=org" -H ldap://localhost:1389 -w secret // ldapsearch -D "CN=manager,DC=example,DC=org" -H "ldap://localhost:1389" -b cn=Monitor -w secret require.Empty(t, acc.Errors, "accumulator had no errors") require.True(t, acc.HasMeasurement("openldap"), "Has a measurement called 'openldap'") require.Equal(t, o.Host, acc.TagValue("openldap", "server"), "Has a tag value of server=o.Host") require.Equal(t, strconv.Itoa(o.Port), acc.TagValue("openldap", "port"), "Has a tag value of port=o.Port") require.True(t, acc.HasInt64Field("openldap", "total_connections"), "Has an integer field called total_connections") } func TestOpenldapReverseMetricsIntegration(t *testing.T) { if testing.Short() { t.Skip("Skipping integration test in short mode") } container := testutil.Container{ Image: "bitnami/openldap", ExposedPorts: []string{servicePort}, Env: map[string]string{ "LDAP_ADMIN_USERNAME": "manager", "LDAP_ADMIN_PASSWORD": "secret", }, WaitingFor: wait.ForAll( wait.ForLog("slapd starting"), wait.ForListeningPort(nat.Port(servicePort)), ), } err := container.Start() require.NoError(t, err, "failed to start container") defer container.Terminate() port, err := strconv.Atoi(container.Ports[servicePort]) require.NoError(t, err) o := &Openldap{ Host: container.Address, Port: port, SSL: "", InsecureSkipVerify: true, BindDn: "CN=manager,DC=example,DC=org", BindPassword: "secret", ReverseMetricNames: true, } var acc testutil.Accumulator err = o.Gather(&acc) require.NoError(t, err) require.True(t, acc.HasInt64Field("openldap", "connections_total"), "Has an integer field called connections_total") }