func Login(user, pass, secret string) (string, error) { if skipLogin { return "dummysecret", nil // just let everything pass } // Checking if we are already logged in var LDAPConn *ldap.LDAPConnection req := &Request{user, secret, false, make(chan bool)} LookupSession(req) if !req.LoggedIn { LDAPConn = ldap.NewLDAPSSLConnection(LdapServer, LdapPort, TlsConfig) err := LDAPConn.Connect() if err != nil { return "", err } err = LoginBind(user, pass, LDAPConn) if err != nil { return "", err } now := strconv.FormatInt(time.Now().Unix(), 10) sec := string(crypto.Encrypt([]byte(pass + now))) re := regexp.MustCompile("[^a-zA-Z0-9]") sec = re.ReplaceAllString(sec, "") req.Secret = sec } CreateSession(req, LDAPConn) return req.Secret, nil }
func LdapAuthenticator(options *LdapOptions) (martini.Handler, error) { hostInfo := HostExpr.FindStringSubmatch(options.Host) config := &ldapConfig{} switch hostInfo[1] { case "ldap": config.SSL = false case "ldaps": config.SSL = true default: return nil, fmt.Errorf("invalid ldap protocol: %s", hostInfo[1]) } config.Host = hostInfo[2] if hostInfo[4] != "" { port, err := strconv.ParseUint(hostInfo[4], 10, 16) if err != nil { return nil, fmt.Errorf("unable to parse ldap port: %s", err) } config.Port = uint16(port) } else { if config.SSL { config.Port = 636 } else { config.Port = 389 } } return func(res http.ResponseWriter, req *http.Request, c martini.Context, log *log.Logger) { // HACK TODO: do not put routing logic in the auth handler // The /ping endpoint does not have auth, so explicitly exclude it here if req.URL.Path == "/ping" { return } authHandler := auth.BasicFunc(func(username, password string) bool { // create the ldap server connection var conn *ldap.LDAPConnection if config.SSL { tlsConfig := tls.Config{ ServerName: config.Host, } conn = ldap.NewLDAPSSLConnection(config.Host, config.Port, &tlsConfig) } else { conn = ldap.NewLDAPConnection(config.Host, config.Port) } // attempt to connect to the ldap server if err := conn.Connect(); err != nil { log.Printf("Unable to connect to LDAP: %s", err) return false } // perform an anonymous search for the user's dn so we can attempt to bind as them req := ldap.SearchRequest{ BaseDN: options.BaseDN, Filter: fmt.Sprintf(options.UserFilter, ldap.EscapeFilterValue(username)), Scope: ldap.ScopeWholeSubtree, } res, err := conn.Search(&req) if err != nil { log.Printf("Error performing LDAP search: %s", err) return false } // Return false if the number of entries isn't exactly 1. If multiple // results were returned, there is an ambiguity so return false instead // of proceeding. If no entries were returned, we have no idea who this // is and cannot authenticate. if len(res.Entries) != 1 { if len(res.Entries) > 1 { log.Printf("User '%s' attempted to authenticate but multiple entries exists", username) } else { log.Printf("User '%s' attempted to authenticate but does not exist", username) } return false } dn := res.Entries[0].DN if err := conn.Bind(dn, password); err != nil { log.Printf("User '%s' attempted to authenticate but provided an invalid password", username) return false } log.Printf("Authenticated successfully as %s", username) return true }) authenticate := authHandler.(func(http.ResponseWriter, *http.Request, martini.Context)) authenticate(res, req, c) }, nil }