Skip to content

Commit

Permalink
feat: add ability to run ldap search
Browse files Browse the repository at this point in the history
  • Loading branch information
Adriel Perkins committed Mar 24, 2023
1 parent ad73d69 commit 2d642d5
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 18 deletions.
25 changes: 20 additions & 5 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import (

// Configuration that is exposed to this ldapreceiver through the OTEL config.yaml
type Config struct {
Interval string `mapstructure:"interval"`
Interval string `mapstructure:"interval"`
SearchFilter string `mapstructure:"search_filter"`
Endpoint string `mapstructure:"endpoint"`
BaseDN string `mapstructure:"base_dn"`
InsecureSkipVerify bool `mapstructure:"ignore_tls"`

// TODO: either implement ASM authenticator, or leverage the basic auth extension (preferrable)
//ASMEnabled bool `mapstructure:"asm_enabled"`
//UserSecretName string `mapstructure:"user_secret_name"`
//PassSecretName string `mapstructure:"pass_secret_name"`
// TODO: replace with basic auth through OTel configuration
User string `mapstructure:"user"`
Pw string `mapstructure:"pw"`
}

// Validate the configuration passed through the OTEL config.yaml
Expand All @@ -21,5 +24,17 @@ func (cfg *Config) Validate() error {
if interval.Seconds() < 10 {
return fmt.Errorf("interval must be at least 10 seconds")
}

if cfg.SearchFilter == "" {
return fmt.Errorf("search_filter must be set")
}

if cfg.BaseDN == "" {
return fmt.Errorf("base_dn must be set")
}

if cfg.Endpoint == "" {
return fmt.Errorf("endpoint must be set")
}
return nil
}
12 changes: 7 additions & 5 deletions factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import (
)

const (
typeStr = "ldap"
defaultInterval = 10 * time.Second
defaultTimeout = 10 * time.Second
stability = component.StabilityLevelAlpha
typeStr = "ldap"
defaultInterval = 10 * time.Second
defaultIgnoreTLS = false
defaultTimeout = 10 * time.Second
stability = component.StabilityLevelAlpha
)

var (
Expand All @@ -25,7 +26,8 @@ var (
// Create ethe default config based on the const(s) defined above.
func createDefaultConfig() component.Config {
return &Config{
Interval: fmt.Sprint(defaultInterval),
Interval: fmt.Sprint(defaultInterval),
InsecureSkipVerify: defaultIgnoreTLS,
}
}

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.20

require (
github.com/go-ldap/ldap/v3 v3.4.4
github.com/go-playground/assert/v2 v2.2.0
go.opentelemetry.io/collector/component v0.73.0
go.opentelemetry.io/collector/consumer v0.73.0
go.opentelemetry.io/collector/receiver v0.73.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXg
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
Expand Down
44 changes: 36 additions & 8 deletions scraper.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package ldapreceiver
import (
"context"
"crypto/tls"
"fmt"
"log"
"time"

"github.com/go-ldap/ldap/v3"
Expand All @@ -21,16 +23,13 @@ type ldapReceiver struct {

// Insantiate the client connection to LDAP
func ldapClient(ldapRcvr *ldapReceiver) *ldap.Conn {
//user := strings.Join([]string{"LUV", creds.Username}, "\\")
//pw := creds.Password
// TODO: replace with what is above coming from OTEL config
user := "cn=admin,dc=example,dc=org"
pw := "admin"
// TODO: replace with basic auth through OTel configuration
user := ldapRcvr.config.User
pw := ldapRcvr.config.Pw

//#nosec G402 (CWE-295) ignore InsecureSkipVerify TLS setting due to self-signed certificates and network isolation
// TODO: LDAP config should come from OTEL config.yaml
//connection, err := ldap.DialURL("ldaps://<configured>:636", ldap.DialWithTLSConfig(&tls.Config{InsecureSkipVerify: SkipTlsVerification}))
connection, err := ldap.DialURL("ldaps://localhost:636", ldap.DialWithTLSConfig(&tls.Config{InsecureSkipVerify: true}))
endpoint := fmt.Sprint("ldaps://", ldapRcvr.config.Endpoint, ":636")
connection, err := ldap.DialURL(endpoint, ldap.DialWithTLSConfig(&tls.Config{InsecureSkipVerify: ldapRcvr.config.InsecureSkipVerify}))
if err != nil {
ldapRcvr.logger.Sugar().Fatalf("Error dialing ldap server %v", err)
}
Expand All @@ -45,6 +44,34 @@ func ldapClient(ldapRcvr *ldapReceiver) *ldap.Conn {
return connection
}

// Get the results from an ldapsearch by making a connection to LDAP and returning the search
func getResults(conn *ldap.Conn, ldapRcvr *ldapReceiver) (search *ldap.SearchResult) {
search = performSearch(conn, fmt.Sprint(ldapRcvr.config.SearchFilter), ldapRcvr)

ldapRcvr.logger.Sugar().Debugf("Number of returned Entries: %d", len(search.Entries))

return
}

// Perform a search query in LDAP and return the result
func performSearch(conn *ldap.Conn, query string, ldapRcvr *ldapReceiver) (result *ldap.SearchResult) {
sr := ldap.NewSearchRequest(
ldapRcvr.config.BaseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0,
false,
query,
[]string{"member"},
nil,
)

result, err := conn.Search(sr)
if err != nil {
log.Fatalf("error with searching request: %v", err)
}

return result
}

func (ldapRcvr *ldapReceiver) Start(ctx context.Context, host component.Host) error {
ldapRcvr.host = host
ctx = context.Background()
Expand All @@ -62,6 +89,7 @@ func (ldapRcvr *ldapReceiver) Start(ctx context.Context, host component.Host) er
select {
case <-ticker.C:
ldapRcvr.logger.Info("Processing metrics..")
getResults(ldapConn, ldapRcvr)
case <-ctx.Done():
return
}
Expand Down
1 change: 1 addition & 0 deletions scraper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package ldapreceiver
7 changes: 7 additions & 0 deletions testdata/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ receivers:
grpc:
ldap:
interval: 10s
search_filter: "(&(objectClass=group)(|MyGroup*))"
endpoint: "localhost"
# TODO: use basic auth
user: "cn=admin,dc=example,dc=org"
pw: "admin"
base_dn: "DC=LUV,DC=AD,DC=SWACORP,DC=com"

#ldap:
# interval: "10"
# #ldapreceiver:
Expand Down

0 comments on commit 2d642d5

Please sign in to comment.