diff --git a/Dockerfile.dev b/Dockerfile.dev index 2a3ab15..82cba68 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -13,7 +13,6 @@ COPY ./main.go ./ COPY ./air.toml ./ RUN go install github.com/air-verse/air@v1.61.7 -RUN go install github.com/go-delve/delve/cmd/dlv@v1.25.0 EXPOSE 3000 diff --git a/air.toml b/air.toml index 466d56e..7505b79 100644 --- a/air.toml +++ b/air.toml @@ -2,9 +2,9 @@ root = "/tinyauth" tmp_dir = "tmp" [build] -pre_cmd = ["mkdir -p internal/assets/dist", "echo 'backend running' > internal/assets/dist/index.html"] -cmd = "CGO_ENABLED=0 go build -gcflags=\"all=-N -l\" -o ./tinyauth ." -bin = "/go/bin/dlv --listen :4000 --headless=true --api-version=2 --accept-multiclient --log=true exec ./tinyauth" +pre_cmd = ["mkdir -p internal/assets/dist", "echo 'backend running' > internal/assets/dist/index.html", "go install github.com/go-delve/delve/cmd/dlv@v1.25.0"] +cmd = "CGO_ENABLED=0 go build -gcflags=\"all=-N -l\" -o tmp/tinyauth ." +bin = "/go/bin/dlv --listen :4000 --headless=true --api-version=2 --accept-multiclient --log=true exec tmp/tinyauth --continue" include_ext = ["go"] exclude_dir = ["internal/assets/dist"] exclude_regex = [".*_test\\.go"] diff --git a/internal/ldap/ldap.go b/internal/ldap/ldap.go index 4a33f46..c380fd4 100644 --- a/internal/ldap/ldap.go +++ b/internal/ldap/ldap.go @@ -3,38 +3,61 @@ package ldap import ( "crypto/tls" "fmt" + "time" "tinyauth/internal/types" ldapgo "github.com/go-ldap/ldap/v3" + "github.com/rs/zerolog/log" ) type LDAP struct { Config types.LdapConfig Conn *ldapgo.Conn - BaseDN string } func NewLDAP(config types.LdapConfig) (*LDAP, error) { + // Create a new LDAP instance with the provided configuration + ldap := &LDAP{ + Config: config, + } + // Connect to the LDAP server - conn, err := ldapgo.DialURL(config.Address, ldapgo.DialWithTLSConfig(&tls.Config{ - InsecureSkipVerify: config.Insecure, + if err := ldap.Connect(); err != nil { + return nil, fmt.Errorf("failed to connect to LDAP server: %w", err) + } + + // Start heartbeat goroutine + go func() { + for range time.Tick(time.Duration(5) * time.Minute) { + err := ldap.heartbeat() + if err != nil { + log.Error().Err(err).Msg("LDAP connection heartbeat failed") + } + } + }() + + return ldap, nil +} + +func (l *LDAP) Connect() error { + // Connect to the LDAP server + conn, err := ldapgo.DialURL(l.Config.Address, ldapgo.DialWithTLSConfig(&tls.Config{ + InsecureSkipVerify: l.Config.Insecure, MinVersion: tls.VersionTLS12, })) if err != nil { - return nil, err + return err } // Bind to the LDAP server with the provided credentials - err = conn.Bind(config.BindDN, config.BindPassword) + err = conn.Bind(l.Config.BindDN, l.Config.BindPassword) if err != nil { - return nil, err + return err } - return &LDAP{ - Config: config, - Conn: conn, - BaseDN: config.BaseDN, - }, nil + // Store the connection in the LDAP struct + l.Conn = conn + return nil } func (l *LDAP) Search(username string) (string, error) { @@ -44,7 +67,7 @@ func (l *LDAP) Search(username string) (string, error) { // Create a search request to find the user by username searchRequest := ldapgo.NewSearchRequest( - l.BaseDN, + l.Config.BaseDN, ldapgo.ScopeWholeSubtree, ldapgo.NeverDerefAliases, 0, 0, false, filter, []string{"dn"}, @@ -75,3 +98,26 @@ func (l *LDAP) Bind(userDN string, password string) error { } return nil } + +func (l *LDAP) heartbeat() error { + // Perform a simple search to check if the connection is alive + log.Info().Msg("Performing LDAP connection heartbeat") + + // Create a search request to find the user by username + searchRequest := ldapgo.NewSearchRequest( + l.Config.BaseDN, + ldapgo.ScopeWholeSubtree, ldapgo.NeverDerefAliases, 0, 0, false, + "(uid=*)", + []string{}, + nil, + ) + + // Perform the search + _, err := l.Conn.Search(searchRequest) + if err != nil { + return err + } + + // No error means the connection is alive + return nil +}