From 80fcb09a4c5e33264117b9745ca09fe7f294c178 Mon Sep 17 00:00:00 2001 From: Matt Ouille Date: Sun, 9 Feb 2020 00:17:10 -0800 Subject: [PATCH 1/3] Add LDAP support --- Gopkg.lock | 19 ++++++++++++- irc/accounts.go | 76 ++++++++++++++++++++++++++++++++++++++++++++++++- irc/config.go | 23 +++++++++++++++ 3 files changed, 116 insertions(+), 2 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 39b284c78..147848644 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -17,6 +17,22 @@ pruneopts = "UT" revision = "ee0de3bc6815ee19d4a46c7eb90f829db0e014b1" +[[projects]] + digest = "1:c30a38ce87f5727ec45bfb8c8b965a004ab8c70149b082ef96341731ab69eebe" + name = "github.com/go-asn1-ber/asn1-ber" + packages = ["."] + pruneopts = "UT" + revision = "effdc98edfb5dde0d9fd8dfba266f6483e6ce9f0" + version = "v1.4.1" + +[[projects]] + digest = "1:64f3b98bfb2cc6d5fdbada1bf2f1bee5b57cbf3a094c1dde85af44311be53a2e" + name = "github.com/go-ldap/ldap" + packages = ["."] + pruneopts = "UT" + revision = "0e14253abf0be63b8f3159f5014f289337ed3db1" + version = "v3.1.6" + [[projects]] branch = "master" digest = "1:148948635cfd8724af31d43ed024dac11c2b87c27a2a3eeb6c04e7360ab56366" @@ -212,6 +228,7 @@ input-imports = [ "code.cloudfoundry.org/bytefmt", "github.com/docopt/docopt-go", + "github.com/go-ldap/ldap", "github.com/goshuirc/irc-go/ircfmt", "github.com/goshuirc/irc-go/ircmatch", "github.com/goshuirc/irc-go/ircmsg", @@ -224,8 +241,8 @@ "golang.org/x/crypto/sha3", "golang.org/x/crypto/ssh/terminal", "golang.org/x/text/cases", - "golang.org/x/text/language", "golang.org/x/text/secure/precis", + "golang.org/x/text/unicode/norm", "golang.org/x/text/width", "gopkg.in/yaml.v2", ] diff --git a/irc/accounts.go b/irc/accounts.go index 67e3d0c56..821d77a91 100644 --- a/irc/accounts.go +++ b/irc/accounts.go @@ -4,6 +4,7 @@ package irc import ( + "crypto/tls" "encoding/json" "fmt" "net/smtp" @@ -14,6 +15,7 @@ import ( "time" "unicode" + "github.com/go-ldap/ldap" "github.com/oragono/oragono/irc/caps" "github.com/oragono/oragono/irc/passwd" "github.com/oragono/oragono/irc/utils" @@ -828,8 +830,80 @@ func (am *AccountManager) checkPassphrase(accountName, passphrase string) (accou return } +func (am *AccountManager) checkLDAPPassphrase(accountName, passphrase string) (account ClientAccount, err error) { + var ( + host, url string + port int + ) + + host = am.server.AccountConfig().LDAP.Servers.Host + port = am.server.AccountConfig().LDAP.Servers.Port + + account, err = am.LoadAccount(accountName) + if err != nil { + return + } + + if !account.Verified { + err = errAccountUnverified + return + } + + if am.server.AccountConfig().LDAP.Servers.UseSSL { + url = fmt.Sprintf("ldaps://%s:%d", host, port) + } else { + url = fmt.Sprintf("ldap://%s:%d", host, port) + } + + l, err := ldap.DialURL(url) + if err != nil { + return + } + defer l.Close() + + if am.server.AccountConfig().LDAP.Servers.StartTLS { + err = l.StartTLS(&tls.Config{InsecureSkipVerify: am.server.AccountConfig().LDAP.Servers.SkipTLSVerify}) + if err != nil { + return + } + } + + err = l.Bind(am.server.AccountConfig().LDAP.BindDN, am.server.AccountConfig().LDAP.BindPwd) + if err != nil { + return + } + + for _, baseDN := range am.server.AccountConfig().LDAP.SearchBaseDNs { + req := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, am.server.AccountConfig().LDAP.Timeout, false, fmt.Sprintf("(&(objectClass=organizationalPerson)(uid=%s))", accountName), []string{"dn"}, nil) + sr, err := l.Search(req) + if err != nil { + return + } + + userdn := sr.Entries[0].DN + + if len(sr.Entries) > 0 { + // verify the user passphrase + err = l.Bind(userdn, passphrase) + if err != nil { + continue + } + break + } + } + + return +} + func (am *AccountManager) AuthenticateByPassphrase(client *Client, accountName string, passphrase string) error { - account, err := am.checkPassphrase(accountName, passphrase) + var account ClientAccount + var err error + + if am.server.AccountConfig().LDAP.Enabled { + account, err = am.checkLDAPPassphrase(accountName, passphrase) + } + + account, err = am.checkPassphrase(accountName, passphrase) if err != nil { return err } diff --git a/irc/config.go b/irc/config.go index 361cd15f7..6a3158352 100644 --- a/irc/config.go +++ b/irc/config.go @@ -68,6 +68,7 @@ type AccountConfig struct { Exempted []string exemptedNets []net.IPNet } `yaml:"require-sasl"` + LDAP LDAPConfig LoginThrottling struct { Enabled bool Duration time.Duration @@ -82,6 +83,28 @@ type AccountConfig struct { VHosts VHostConfig } +type LDAPConfig struct { + Timeout int + Enabled bool + AllowSignup bool `yaml:"allow-signup"` + BindDN string `yaml:"bind-dn"` + BindPwd string `yaml:"bind-password"` + SearchFilter string `yaml:"search-filter"` + SearchBaseDNs []string `yaml:"search-base-dns"` + Attributes map[string]string + Servers LDAPServerConfig +} + +type LDAPServerConfig struct { + Host string + Port int + UseSSL bool `yaml:"use-ssl"` + StartTLS bool `yaml:"start-tls"` + SkipTLSVerify bool `yaml:"skip-tls-verify"` + ClientCert string `yaml:"client-cert"` + ClientKey string `yaml:"client-key"` +} + // AccountRegistrationConfig controls account registration. type AccountRegistrationConfig struct { Enabled bool From 4bbcac00d2dc5dde6ca45011d68272084e5ab738 Mon Sep 17 00:00:00 2001 From: Matt Ouille Date: Sun, 9 Feb 2020 01:12:42 -0800 Subject: [PATCH 2/3] Fix compilation errors --- irc/accounts.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/irc/accounts.go b/irc/accounts.go index 821d77a91..9638d699d 100644 --- a/irc/accounts.go +++ b/irc/accounts.go @@ -834,6 +834,8 @@ func (am *AccountManager) checkLDAPPassphrase(accountName, passphrase string) (a var ( host, url string port int + sr *ldap.SearchResult + l *ldap.Conn ) host = am.server.AccountConfig().LDAP.Servers.Host @@ -855,7 +857,7 @@ func (am *AccountManager) checkLDAPPassphrase(accountName, passphrase string) (a url = fmt.Sprintf("ldap://%s:%d", host, port) } - l, err := ldap.DialURL(url) + l, err = ldap.DialURL(url) if err != nil { return } @@ -875,7 +877,7 @@ func (am *AccountManager) checkLDAPPassphrase(accountName, passphrase string) (a for _, baseDN := range am.server.AccountConfig().LDAP.SearchBaseDNs { req := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, am.server.AccountConfig().LDAP.Timeout, false, fmt.Sprintf("(&(objectClass=organizationalPerson)(uid=%s))", accountName), []string{"dn"}, nil) - sr, err := l.Search(req) + sr, err = l.Search(req) if err != nil { return } @@ -901,6 +903,10 @@ func (am *AccountManager) AuthenticateByPassphrase(client *Client, accountName s if am.server.AccountConfig().LDAP.Enabled { account, err = am.checkLDAPPassphrase(accountName, passphrase) + if err == nil { + am.Login(client, account) + return nil + } } account, err = am.checkPassphrase(accountName, passphrase) From 5759877fa6902490fd444d6498ee6dd27bc1fd71 Mon Sep 17 00:00:00 2001 From: Matt Ouille Date: Sun, 9 Feb 2020 01:13:02 -0800 Subject: [PATCH 3/3] Update Gopkg.lock --- Gopkg.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 147848644..814d15417 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -3,11 +3,11 @@ [[projects]] branch = "master" - digest = "1:805d31e8de22d8be01b05e29eb3d1a02e512c9d437724372afe3e9cd45a1cf87" + digest = "1:c5f3f73b4b9a2a086ff3fc72bb3dbe128e2304d8f0501efa057ae1ede0c03993" name = "code.cloudfoundry.org/bytefmt" packages = ["."] pruneopts = "UT" - revision = "854d396b647c90b5a45646f9dcc2c9cd08ea8d51" + revision = "cf55d5288a48262e16d2e628b6221dd2df67bcd1" [[projects]] branch = "master" @@ -62,12 +62,12 @@ version = "v0.1.4" [[projects]] - digest = "1:d62282425ffb75047679d7e2c3b980eea7f82c05ef5fb9142ee617ebac6e7432" + digest = "1:0c58d31abe2a2ccb429c559b6292e7df89dcda675456fecc282fa90aa08273eb" name = "github.com/mattn/go-isatty" packages = ["."] pruneopts = "UT" - revision = "88ba11cfdc67c7588b30042edf244b2875f892b6" - version = "v0.0.10" + revision = "7b513a986450394f7bbf1476909911b3aa3a55ce" + version = "v0.0.12" [[projects]] branch = "master" @@ -109,12 +109,12 @@ version = "v1.1.2" [[projects]] - digest = "1:5a68167017eaa32aa408397806b9d69815244238ed774439a8863ef4bc329eeb" + digest = "1:fcea9aca14ce388baeb3afd42bc3302089393f78f9531212aed88d60a134a921" name = "github.com/tidwall/gjson" packages = ["."] pruneopts = "UT" - revision = "c34bf81952c067718854115564f8e55978be5e1d" - version = "v1.3.4" + revision = "d10932a0d0b5f1618759b6259b05f7cb7bea0c25" + version = "v1.4.0" [[projects]] branch = "master" @@ -133,12 +133,12 @@ version = "v1.0.1" [[projects]] - digest = "1:ddfe0a54e5f9b29536a6d7b2defa376f2cb2b6e4234d676d7ff214d5b097cb50" + digest = "1:f63bab79e68e805cdd9bf70daa09e8c430cfbddf29d14b567a92fb12581b9b95" name = "github.com/tidwall/pretty" packages = ["."] pruneopts = "UT" - revision = "1166b9ac2b65e46a43d8618d30d1554f4652d49b" - version = "v1.0.0" + revision = "b2475501f89994f7ea30b3c94ba86b49079961fe" + version = "v1.0.1" [[projects]] branch = "master" @@ -161,7 +161,7 @@ [[projects]] branch = "master" - digest = "1:ee7263bc4399e2ed4f28e3c9c2e661218d427e4e4e4501748080aae41e6942ba" + digest = "1:0af7de6d849a5ac8579ad02b7de873697b80876af34f676fe8bcdbd673d586aa" name = "golang.org/x/crypto" packages = [ "bcrypt", @@ -170,11 +170,11 @@ "ssh/terminal", ] pruneopts = "UT" - revision = "e1110fd1c708ef015366ea01799a23c459593c47" + revision = "ecb85df213405b7d32e4d73cb5bbaace2ec88881" [[projects]] branch = "master" - digest = "1:5d507fb4c4f49b851691887afc8a5a547634186965f85209cc1f25a3ab6a6c57" + digest = "1:82a36a77bd0e9b96345f621e6fe74a83261bb09f1ec3863328420ac5198e7510" name = "golang.org/x/sys" packages = [ "cpu", @@ -182,7 +182,7 @@ "windows", ] pruneopts = "UT" - revision = "52ab431487773bc9dd1b0766228b1cf3944126bf" + revision = "d101bd2416d505c0448a6ce8a282482678040a89" [[projects]] digest = "1:5f1559c4cee44069f81517430ebba19589869f3d4d4648213a4d5ddd199b11d8" @@ -215,12 +215,12 @@ version = "v0.3.2" [[projects]] - digest = "1:f26a5d382387e03a40d1471dddfba85dfff9bf05352d7e42d37612677c4d3c5c" + digest = "1:55b110c99c5fdc4f14930747326acce56b52cfce60b24b1c03ef686ac0e46bb1" name = "gopkg.in/yaml.v2" packages = ["."] pruneopts = "UT" - revision = "f90ceb4f409096b60e2e9076b38b304b8246e5fa" - version = "v2.2.5" + revision = "53403b58ad1b561927d19068c655246f2db79d48" + version = "v2.2.8" [solve-meta] analyzer-name = "dep"