From 221b9deaaa1a3a9a417c4b7a465f85d74692a7ad Mon Sep 17 00:00:00 2001 From: gsw945 Date: Fri, 2 Sep 2022 10:41:35 +0800 Subject: [PATCH] =?UTF-8?q?ldap=E7=99=BB=E5=BD=95=E6=97=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E9=82=AE=E7=AE=B1=E4=BD=9C=E4=B8=BA=E8=B4=A6=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf/app.conf.example | 4 ++- dev-win-build.cmd | 1 + go.mod | 5 ++- go.sum | 17 ++++++++--- models/Member.go | 71 ++++++++++++++++++++++++++++++++++--------- 5 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 dev-win-build.cmd diff --git a/conf/app.conf.example b/conf/app.conf.example index 70e70018..5be84b28 100644 --- a/conf/app.conf.example +++ b/conf/app.conf.example @@ -125,7 +125,9 @@ ldap_host=ad.example.com #ldap端口 ldap_port=3268 #ldap内哪个属性作为用户名 -ldap_attribute=sAMAccountName +ldap_account=sAMAccountName +#ldap内哪个属性作为邮箱 +ldap_mail=mail #搜索范围 ldap_base=DC=example,DC=com #第一次绑定ldap用户dn diff --git a/dev-win-build.cmd b/dev-win-build.cmd new file mode 100644 index 00000000..5dcb191f --- /dev/null +++ b/dev-win-build.cmd @@ -0,0 +1 @@ +go build -v -ldflags "-linkmode external -extldflags '-static' -w" -o mindoc_windows_amd64.exe main.go \ No newline at end of file diff --git a/go.mod b/go.mod index 76e16c98..1d0242ab 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/beego/beego/v2 v2.0.5 github.com/beego/i18n v0.0.0-20161101132742-e9308947f407 github.com/boombuler/barcode v1.0.1 + github.com/go-ldap/ldap/v3 v3.4.4 github.com/howeyc/fsnotify v0.9.0 github.com/kardianos/service v1.2.1 github.com/lifei6671/gocaptcha v0.2.0 @@ -18,11 +19,13 @@ require ( ) require ( + github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect github.com/Unknwon/goconfig v1.0.0 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-redis/redis/v7 v7.4.1 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect @@ -38,7 +41,7 @@ require ( github.com/prometheus/procfs v0.8.0 // indirect github.com/rivo/uniseg v0.3.4 // indirect github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect - github.com/smartystreets/goconvey v1.6.4 // indirect + github.com/smartystreets/goconvey v1.7.2 // indirect golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d // indirect golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b // indirect diff --git a/go.sum b/go.sum index 68305d3e..ea7bcc68 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU= +github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= @@ -76,6 +78,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-asn1-ber/asn1-ber v1.5.0 h1:/S4hO/AO6tLMlPX0oftGSOcdGJJN/MuYzfgWRMn199E= github.com/go-asn1-ber/asn1-ber v1.5.0/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= +github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -83,6 +87,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs= +github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI= 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= @@ -250,15 +256,16 @@ github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -274,6 +281,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -340,6 +348,7 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY= diff --git a/models/Member.go b/models/Member.go index 49916e24..6a3569d3 100644 --- a/models/Member.go +++ b/models/Member.go @@ -15,7 +15,7 @@ import ( "strings" "time" - "gopkg.in/ldap.v2" + "github.com/go-ldap/ldap/v3" "math" @@ -119,14 +119,14 @@ func (m *Member) TmpLogin(account string) (*Member, error) { return member, nil } -//ldapLogin 通过LDAP登陆 +// ldapLogin 通过LDAP登陆 func (m *Member) ldapLogin(account string, password string) (*Member, error) { if !web.AppConfig.DefaultBool("ldap_enable", false) { return m, ErrMemberAuthMethodInvalid } var err error ldaphost, _ := web.AppConfig.String("ldap_host") - lc, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldaphost, web.AppConfig.DefaultInt("ldap_port", 3268))) + lc, err := ldap.DialURL(fmt.Sprintf("ldap://%s:%d", ldaphost, web.AppConfig.DefaultInt("ldap_port", 3268))) if err != nil { logs.Error("绑定 LDAP 用户失败 ->", err) return m, ErrLDAPConnect @@ -141,13 +141,23 @@ func (m *Member) ldapLogin(account string, password string) (*Member, error) { } ldapbase, _ := web.AppConfig.String("ldap_base") ldapfilter, _ := web.AppConfig.String("ldap_filter") - ldapattr, _ := web.AppConfig.String("ldap_attribute") + ldapaccount, _ := web.AppConfig.String("ldap_account") + ldapmail, _ := web.AppConfig.String("ldap_mail") + // 判断account是否是email + isEmail := false + var email string + ldapattr := ldapaccount + if ok, err := regexp.MatchString(conf.RegexpEmail, account); ok && err == nil { + isEmail = true + email = account + ldapattr = ldapmail + } searchRequest := ldap.NewSearchRequest( ldapbase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, - //修改objectClass通过配置文件获取值 + // 修改objectClass通过配置文件获取值 fmt.Sprintf("(&(%s)(%s=%s))", ldapfilter, ldapattr, account), - []string{"dn", "mail"}, + []string{"dn", "mail", "cn", "ou", "sAMAccountName"}, nil, ) searchResult, err := lc.Search(searchRequest) @@ -164,10 +174,33 @@ func (m *Member) ldapLogin(account string, password string) (*Member, error) { logs.Error("绑定 LDAP 用户失败 ->", err) return m, ErrorMemberPasswordError } + + ldap_cn := searchResult.Entries[0].GetAttributeValue("cn") + ldap_mail := searchResult.Entries[0].GetAttributeValue(ldapmail) // "mail" + ldap_account := searchResult.Entries[0].GetAttributeValue(ldapaccount) // "sAMAccountName" + + m.RealName = ldap_cn + m.Account = ldap_account + m.AuthMethod = "ldap" + // 如果ldap配置了email + if len(ldap_mail) > 0 && strings.Contains(ldap_mail, "@") { + // 如果member已配置email + if len(m.Email) > 0 { + // 如果member配置的email和ldap配置的email不同 + if m.Email != ldap_mail { + return m, errors.New(fmt.Sprintf("ldap配置的email(%s)与数据库中已有email({%s})不同, 请联系管理员修改", ldap_mail, m.Email)) + } + } else { + // 如果member未配置email,则用ldap的email配置 + m.Email = ldap_mail + } + } else { + // 如果ldap未配置email,则直接绑定到member + if isEmail { + m.Email = email + } + } if m.MemberId <= 0 { - m.Account = account - m.Email = searchResult.Entries[0].GetAttributeValue("mail") - m.AuthMethod = "ldap" m.Avatar = "/static/images/headimgurl.jpg" m.Role = conf.SystemRole(web.AppConfig.DefaultInt("ldap_user_role", 2)) m.CreateTime = time.Now() @@ -178,6 +211,14 @@ func (m *Member) ldapLogin(account string, password string) (*Member, error) { return m, ErrorMemberPasswordError } m.ResolveRoleName() + } else { + // 更新ldap信息 + err = m.Update("account", "real_name", "email", "auth_method") + if err != nil { + logs.Error("LDAP更新用户信息失败", err) + return m, errors.New("LDAP更新用户信息失败") + } + m.ResolveRoleName() } return m, nil } @@ -338,7 +379,7 @@ func (m *Member) ResolveRoleName() { } } -//根据账号查找用户. +// 根据账号查找用户. func (m *Member) FindByAccount(account string) (*Member, error) { o := orm.NewOrm() @@ -350,7 +391,7 @@ func (m *Member) FindByAccount(account string) (*Member, error) { return m, err } -//批量查询用户 +// 批量查询用户 func (m *Member) FindByAccountList(accounts ...string) ([]*Member, error) { o := orm.NewOrm() @@ -365,7 +406,7 @@ func (m *Member) FindByAccountList(accounts ...string) ([]*Member, error) { return members, err } -//分页查找用户. +// 分页查找用户. func (m *Member) FindToPager(pageIndex, pageSize int) ([]*Member, int, error) { o := orm.NewOrm() @@ -399,7 +440,7 @@ func (m *Member) IsAdministrator() bool { return m.Role == 0 || m.Role == 1 } -//根据指定字段查找用户. +// 根据指定字段查找用户. func (m *Member) FindByFieldFirst(field string, value interface{}) (*Member, error) { o := orm.NewOrm() @@ -408,7 +449,7 @@ func (m *Member) FindByFieldFirst(field string, value interface{}) (*Member, err return m, err } -//校验用户. +// 校验用户. func (m *Member) Valid(is_hash_password bool) error { //邮箱不能为空 @@ -464,7 +505,7 @@ func (m *Member) Valid(is_hash_password bool) error { return nil } -//删除一个用户. +// 删除一个用户. func (m *Member) Delete(oldId int, newId int) error { ormer := orm.NewOrm()