func NewLdapConnection() (*ldap.Conn, error) { var err error lh, err := ldapHost() if err != nil { logger.Log(kv{"fn": "NewLdapConnection", "error": err.Error()}) } hoster := strings.Split(lh.Host, ":") port := func() uint16 { if len(hoster) < 2 { return uint16(389) } else { var e error port, e := strconv.Atoi(hoster[1]) if e != nil { panic(e) } return uint16(port) } } var ldapCon *ldap.Conn if strings.Contains(lh.String(), "ldaps") { ldapCon, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", hoster[0], port()), &tls.Config{InsecureSkipVerify: true}) } else { ldapCon, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", hoster[0], port())) } if err != nil { logger.Log(kv{"fn": "NewLdapConnection", "error": err.Error()}) return nil, err } return ldapCon, nil }
func (h ldapHandler) getSession(conn net.Conn) (ldapSession, error) { id := connID(conn) h.lock.Lock() s, ok := h.sessions[id] // use server connection if it exists h.lock.Unlock() if !ok { // open a new server connection if not var l *ldap.Conn server, err := h.getBestServer() // pick the best server if err != nil { return ldapSession{}, err } dest := fmt.Sprintf("%s:%d", server.Hostname, server.Port) if server.Scheme == "ldaps" { tlsCfg := &tls.Config{} if h.cfg.Backend.Insecure { tlsCfg.InsecureSkipVerify = true } l, err = ldap.DialTLS("tcp", dest, tlsCfg) } else if server.Scheme == "ldap" { l, err = ldap.Dial("tcp", dest) } if err != nil { select { case h.doPing <- true: // non-blocking send default: } return ldapSession{}, err } s = ldapSession{id: id, c: conn, ldap: l} h.lock.Lock() h.sessions[s.id] = s h.lock.Unlock() } return s, nil }
func (h ldapHandler) ping() error { healthy := false for k, s := range h.servers { var l *ldap.Conn var err error dest := fmt.Sprintf("%s:%d", s.Hostname, s.Port) start := time.Now() if h.servers[0].Scheme == "ldaps" { tlsCfg := &tls.Config{} if h.cfg.Backend.Insecure { tlsCfg.InsecureSkipVerify = true } l, err = ldap.DialTLS("tcp", dest, tlsCfg) } else if h.servers[0].Scheme == "ldap" { l, err = ldap.Dial("tcp", dest) } elapsed := time.Since(start) h.lock.Lock() if err != nil || l == nil { log.Error(fmt.Sprintf("Server %s:%d ping failed: %s", s.Hostname, s.Port, err.Error())) h.servers[k].Ping = 0 h.servers[k].Status = Down } else { healthy = true h.servers[k].Ping = elapsed h.servers[k].Status = Up l.Close() // prank caller } h.lock.Unlock() } log.Debug("Server health: %# v", pretty.Formatter(h.servers)) b, err := json.Marshal(h.servers) if err != nil { log.Error(fmt.Sprintf("Error encoding tail data: %s", err.Error())) } stats_backend.Set("servers", stringer(string(b))) if healthy == false { return fmt.Errorf("No healthy servers") } return nil }
func main() { l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", LdapServer, LdapPort), nil) if err != nil { log.Fatalf("ERROR: %s\n", err.Error()) } defer l.Close() // l.Debug = true search := ldap.NewSearchRequest( BaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, Filter, Attributes, nil) sr, err := l.Search(search) if err != nil { log.Fatalf("ERROR: %s\n", err.Error()) return } log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries)) sr.PrettyPrint(0) }
func main() { // Parse command-line flags for this system. var ( listenAddress = flag.String("addr", "", "Address to listen to incoming requests on.") ldapAddress = flag.String("ldapAddr", "", "Address to connect to LDAP.") ldapBindDN = flag.String("ldapBindDN", "", "LDAP DN to bind to for login.") ldapInsecure = flag.Bool("insecureLDAP", false, "INSECURE: Don't use TLS for LDAP connection.") ldapBindPassword = flag.String("ldapBindPassword", "", "LDAP password for bind.") statsdHost = flag.String("statsHost", "", "Address to send statsd metrics to.") iamAccount = flag.String("iamaccount", "", "AWS Account ID for generating IAM Role ARNs") enableLDAPRoles = flag.Bool("ldaproles", false, "Enable role support using LDAP directory.") roleAttribute = flag.String("roleattribute", "", "Group attribute to get role from.") defaultRole = flag.String("role", "", "AWS role to assume by default.") configFile = flag.String("conf", "/etc/hologram/server.json", "Config file to load.") cacheTimeout = flag.Int("cachetime", 3600, "Time in seconds after which to refresh LDAP user cache.") debugMode = flag.Bool("debug", false, "Enable debug mode.") config Config ) flag.Parse() // Enable debug log output if the user requested it. if *debugMode { log.DebugMode(true) log.Debug("Enabling debug log output. Use sparingly.") } // Parse in options from the given config file. log.Debug("Loading configuration from %s", *configFile) configContents, configErr := ioutil.ReadFile(*configFile) if configErr != nil { log.Errorf("Could not read from config file. The error was: %s", configErr.Error()) os.Exit(1) } configParseErr := json.Unmarshal(configContents, &config) if configParseErr != nil { log.Errorf("Error in parsing config file: %s", configParseErr.Error()) os.Exit(1) } // Merge in command flag options. if *ldapAddress != "" { config.LDAP.Host = *ldapAddress } if *ldapInsecure { config.LDAP.InsecureLDAP = true } if *ldapBindDN != "" { config.LDAP.Bind.DN = *ldapBindDN } if *ldapBindPassword != "" { config.LDAP.Bind.Password = *ldapBindPassword } if *statsdHost != "" { config.Stats = *statsdHost } if *iamAccount != "" { config.AWS.Account = *iamAccount } if *listenAddress != "" { config.Listen = *listenAddress } if *defaultRole != "" { config.AWS.DefaultRole = *defaultRole } if *enableLDAPRoles { config.LDAP.EnableLDAPRoles = true } if *roleAttribute != "" { config.LDAP.RoleAttribute = *roleAttribute } if *cacheTimeout != 3600 { config.CacheTimeout = *cacheTimeout } var stats g2s.Statter var statsErr error if config.LDAP.UserAttr == "" { config.LDAP.UserAttr = "cn" } if config.Stats == "" { log.Debug("No statsd server specified; no metrics will be emitted by this program.") stats = g2s.Noop() } else { stats, statsErr = g2s.Dial("udp", config.Stats) if statsErr != nil { log.Errorf("Error connecting to statsd: %s. No metrics will be emitted by this program.", statsErr.Error()) stats = g2s.Noop() } else { log.Debug("This program will emit metrics to %s", config.Stats) } } // Setup the server state machine that responds to requests. auth, err := aws.GetAuth(os.Getenv("HOLOGRAM_AWSKEY"), os.Getenv("HOLOGRAM_AWSSECRET"), "", time.Now()) if err != nil { log.Errorf("Error getting instance credentials: %s", err.Error()) os.Exit(1) } stsConnection := sts.New(auth, aws.Regions["us-east-1"]) credentialsService := server.NewDirectSessionTokenService(config.AWS.Account, stsConnection) var ldapServer *ldap.Conn // Connect to the LDAP server using TLS or not depending on the config if config.LDAP.InsecureLDAP { log.Debug("Connecting to LDAP at server %s (NOT using TLS).", config.LDAP.Host) ldapServer, err = ldap.Dial("tcp", config.LDAP.Host) if err != nil { log.Errorf("Could not dial LDAP! %s", err.Error()) os.Exit(1) } } else { // Connect to the LDAP server with sample credentials. tlsConfig := &tls.Config{ InsecureSkipVerify: true, } log.Debug("Connecting to LDAP at server %s.", config.LDAP.Host) ldapServer, err = ldap.DialTLS("tcp", config.LDAP.Host, tlsConfig) if err != nil { log.Errorf("Could not dial LDAP! %s", err.Error()) os.Exit(1) } } if bindErr := ldapServer.Bind(config.LDAP.Bind.DN, config.LDAP.Bind.Password); bindErr != nil { log.Errorf("Could not bind to LDAP! %s", bindErr.Error()) os.Exit(1) } ldapCache, err := server.NewLDAPUserCache(ldapServer, stats, config.LDAP.UserAttr, config.LDAP.BaseDN, config.LDAP.EnableLDAPRoles, config.LDAP.RoleAttribute) if err != nil { log.Errorf("Top-level error in LDAPUserCache layer: %s", err.Error()) os.Exit(1) } serverHandler := server.New(ldapCache, credentialsService, config.AWS.DefaultRole, stats, ldapServer, config.LDAP.UserAttr, config.LDAP.BaseDN, config.LDAP.EnableLDAPRoles) server, err := remote.NewServer(config.Listen, serverHandler.HandleConnection) // Wait for a signal from the OS to shutdown. terminate := make(chan os.Signal) signal.Notify(terminate, syscall.SIGINT, syscall.SIGTERM) // SIGUSR1 and SIGUSR2 should make Hologram enable and disable debug logging, // respectively. debugEnable := make(chan os.Signal) debugDisable := make(chan os.Signal) signal.Notify(debugEnable, syscall.SIGUSR1) signal.Notify(debugDisable, syscall.SIGUSR2) // SIGHUP should make Hologram server reload its cache of user information // from LDAP. reloadCacheSigHup := make(chan os.Signal) signal.Notify(reloadCacheSigHup, syscall.SIGHUP) // Reload the cache based on time set in configuration cacheTimeoutTicker := time.NewTicker(time.Duration(config.CacheTimeout) * time.Second) log.Info("Hologram server is online, waiting for termination.") WaitForTermination: for { select { case <-terminate: break WaitForTermination case <-debugEnable: log.Info("Enabling debug mode.") log.DebugMode(true) case <-debugDisable: log.Info("Disabling debug mode.") log.DebugMode(false) case <-reloadCacheSigHup: log.Info("Force-reloading user cache.") ldapCache.Update() case <-cacheTimeoutTicker.C: log.Info("Cache timeout. Reloading user cache.") ldapCache.Update() } } log.Info("Caught signal; shutting down now.") server.Close() }
func (o *opts) doquery(q query) (*ldap.SearchResult, error) { sr := &ldap.SearchResult{} // parse the ldap URL u, err := url.Parse(q.ldapURL) if err != nil { return sr, err } var port int if u.Scheme == "ldaps" { port = 636 } else if u.Scheme == "ldap" { port = 389 } else { return sr, fmt.Errorf("Unknown LDAP scheme: %s", u.Scheme) } parts := strings.Split(u.Host, ":") hostname := parts[0] if len(parts) > 1 { port, err = strconv.Atoi(parts[1]) if err != nil { return sr, err } } // connect to the ldap server var l *ldap.Conn if u.Scheme == "ldaps" { tlsConfig := tls.Config{} if o.goklp_insecure_skip_verify { tlsConfig.InsecureSkipVerify = true } l, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", hostname, port), &tlsConfig) if err != nil { return sr, err } } else if u.Scheme == "ldap" { l, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", hostname, port)) if err != nil { return sr, err } } defer l.Close() // do an ldap bind err = l.Bind(q.user, q.passwd) if err != nil { return sr, err } // do the ldap search search := ldap.NewSearchRequest( q.baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, q.filter, q.Attributes, nil) sr, err = l.Search(search) if err != nil { return sr, err } return sr, nil }