ldap login support auto cover attributes
1. support cover attribute by ldap 2. add ldap auto regist config
This commit is contained in:
parent
eb03ccc271
commit
7c86e8f58e
|
@ -14,11 +14,19 @@ ldap:
|
||||||
host: "ldap.example.org"
|
host: "ldap.example.org"
|
||||||
port: 389
|
port: 389
|
||||||
baseDn: "dc=example,dc=org"
|
baseDn: "dc=example,dc=org"
|
||||||
|
# AD: manange@example.org
|
||||||
bindUser: "cn=manager,dc=example,dc=org"
|
bindUser: "cn=manager,dc=example,dc=org"
|
||||||
bindPass: "*******"
|
bindPass: "*******"
|
||||||
# openldap: (&(uid=%s))
|
# openldap: (&(uid=%s))
|
||||||
# AD: (&(sAMAccountName=%s))
|
# AD: (&(sAMAccountName=%s))
|
||||||
authFilter: "(&(uid=%s))"
|
authFilter: "(&(uid=%s))"
|
||||||
|
attributes:
|
||||||
|
dispname: "cn"
|
||||||
|
email: "mail"
|
||||||
|
phone: "mobile"
|
||||||
|
im: ""
|
||||||
|
coverAttributes: false
|
||||||
|
autoRegist: false
|
||||||
tls: false
|
tls: false
|
||||||
startTLS: false
|
startTLS: false
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/didi/nightingale/src/modules/monapi/config"
|
||||||
|
"gopkg.in/ldap.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func genLdapAttributeSearchList() []string {
|
||||||
|
ldapAttributes := []string{}
|
||||||
|
attrs := config.Get().LDAP.Attributes
|
||||||
|
if attrs.Dispname != "" {
|
||||||
|
ldapAttributes = append(ldapAttributes, attrs.Dispname)
|
||||||
|
}
|
||||||
|
if attrs.Email != "" {
|
||||||
|
ldapAttributes = append(ldapAttributes, attrs.Email)
|
||||||
|
}
|
||||||
|
if attrs.Phone != "" {
|
||||||
|
ldapAttributes = append(ldapAttributes, attrs.Phone)
|
||||||
|
}
|
||||||
|
if attrs.Im != "" {
|
||||||
|
ldapAttributes = append(ldapAttributes, attrs.Im)
|
||||||
|
}
|
||||||
|
return ldapAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
func ldapReq(user, pass string) (*ldap.SearchResult, error) {
|
||||||
|
var conn *ldap.Conn
|
||||||
|
var err error
|
||||||
|
lc := config.Get().LDAP
|
||||||
|
addr := fmt.Sprintf("%s:%d", lc.Host, lc.Port)
|
||||||
|
|
||||||
|
if lc.TLS {
|
||||||
|
conn, err = ldap.DialTLS("tcp", addr, &tls.Config{InsecureSkipVerify: true})
|
||||||
|
} else {
|
||||||
|
conn, err = ldap.Dial("tcp", addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot dial ldap: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
if !lc.TLS && lc.StartTLS {
|
||||||
|
err = conn.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ldap.conn startTLS fail: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = conn.Bind(lc.BindUser, lc.BindPass)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("bind ldap fail: %v, use %s", err, lc.BindUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
lc.BaseDn, // The base dn to search
|
||||||
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
fmt.Sprintf(lc.AuthFilter, user), // The filter to apply
|
||||||
|
genLdapAttributeSearchList(), // A list attributes to retrieve
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
sr, err := conn.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ldap search fail: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sr.Entries) == 0 {
|
||||||
|
return nil, fmt.Errorf("cannot find such user: %v", user)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sr.Entries) > 1 {
|
||||||
|
return nil, fmt.Errorf("multi users is search, query user: %v", user)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := conn.Bind(sr.Entries[0].DN, pass); err != nil {
|
||||||
|
return nil, fmt.Errorf("password error")
|
||||||
|
}
|
||||||
|
return sr, nil
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -118,6 +117,23 @@ func (u *User) CanModifyTeam(t *Team) (bool, error) {
|
||||||
return cnt > 0, err
|
return cnt > 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) CopyLdapAttr(sr *ldap.SearchResult) {
|
||||||
|
attrs := config.Get().LDAP.Attributes
|
||||||
|
if attrs.Dispname != "" {
|
||||||
|
u.Dispname = sr.Entries[0].GetAttributeValue(attrs.Dispname)
|
||||||
|
}
|
||||||
|
if attrs.Email != "" {
|
||||||
|
u.Email = sr.Entries[0].GetAttributeValue(attrs.Email)
|
||||||
|
}
|
||||||
|
if attrs.Phone != "" {
|
||||||
|
u.Phone = sr.Entries[0].GetAttributeValue(attrs.Phone)
|
||||||
|
}
|
||||||
|
if attrs.Im != "" {
|
||||||
|
u.Im = sr.Entries[0].GetAttributeValue(attrs.Im)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func InitRoot() {
|
func InitRoot() {
|
||||||
var u User
|
var u User
|
||||||
has, err := DB["uic"].Where("username=?", "root").Get(&u)
|
has, err := DB["uic"].Where("username=?", "root").Get(&u)
|
||||||
|
@ -147,78 +163,31 @@ func InitRoot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func LdapLogin(user, pass string) error {
|
func LdapLogin(user, pass string) error {
|
||||||
var conn *ldap.Conn
|
sr, err := ldapReq(user, pass)
|
||||||
var err error
|
|
||||||
|
|
||||||
lc := config.Get().LDAP
|
|
||||||
addr := fmt.Sprintf("%s:%d", lc.Host, lc.Port)
|
|
||||||
|
|
||||||
if lc.TLS {
|
|
||||||
conn, err = ldap.DialTLS("tcp", addr, &tls.Config{InsecureSkipVerify: true})
|
|
||||||
} else {
|
|
||||||
conn, err = ldap.Dial("tcp", addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot dial ldap: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
if !lc.TLS && lc.StartTLS {
|
|
||||||
err = conn.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("ldap.conn startTLS fail: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = conn.Bind(lc.BindUser, lc.BindPass)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bind ldap fail: %v, use %s", err, lc.BindUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
|
||||||
lc.BaseDn, // The base dn to search
|
|
||||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
|
||||||
fmt.Sprintf(lc.AuthFilter, user), // The filter to apply
|
|
||||||
[]string{}, // A list attributes to retrieve
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
|
|
||||||
sr, err := conn.Search(searchRequest)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("ldap search fail: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sr.Entries) == 0 {
|
|
||||||
return fmt.Errorf("cannot find such user: %v", user)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sr.Entries) > 1 {
|
|
||||||
return fmt.Errorf("multi users is search, query user: %v", user)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = conn.Bind(sr.Entries[0].DN, pass)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("password error")
|
|
||||||
}
|
|
||||||
|
|
||||||
cnt, err := DB["uic"].Where("username=?", user).Count(new(User))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cnt > 0 {
|
var u User
|
||||||
return nil
|
has, err := DB["uic"].Where("username=?", user).Get(&u)
|
||||||
}
|
if err != nil {
|
||||||
|
return err
|
||||||
u := &User{
|
}
|
||||||
Username: user,
|
u.CopyLdapAttr(sr)
|
||||||
Password: "******",
|
if has {
|
||||||
Dispname: "",
|
if config.Get().LDAP.CoverAttributes {
|
||||||
Email: "",
|
_, err := DB["uic"].Where("id=?", u.Id).Update(u)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !config.Get().LDAP.AutoRegist {
|
||||||
|
return fmt.Errorf("user has not be created, may be you should enable auto regist: %v", user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u.Username = user
|
||||||
|
u.Password = "******"
|
||||||
_, err = DB["uic"].Insert(u)
|
_, err = DB["uic"].Insert(u)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,14 +64,24 @@ type httpSection struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ldapSection struct {
|
type ldapSection struct {
|
||||||
Host string `yaml:"host"`
|
Host string `yaml:"host"`
|
||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
BaseDn string `yaml:"baseDn"`
|
BaseDn string `yaml:"baseDn"`
|
||||||
BindUser string `yaml:"bindUser"`
|
BindUser string `yaml:"bindUser"`
|
||||||
BindPass string `yaml:"bindPass"`
|
BindPass string `yaml:"bindPass"`
|
||||||
AuthFilter string `yaml:"authFilter"`
|
AuthFilter string `yaml:"authFilter"`
|
||||||
TLS bool `yaml:"tls"`
|
Attributes ldapAttributes `yaml:"attributes"`
|
||||||
StartTLS bool `yaml:"startTLS"`
|
CoverAttributes bool `yaml:"coverAttributes"`
|
||||||
|
AutoRegist bool `yaml:"autoRegist"`
|
||||||
|
TLS bool `yaml:"tls"`
|
||||||
|
StartTLS bool `yaml:"startTLS"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ldapAttributes struct {
|
||||||
|
Dispname string `yaml:"dispname"`
|
||||||
|
Phone string `yaml:"phone"`
|
||||||
|
Email string `yaml:"email"`
|
||||||
|
Im string `yaml:"im"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
Loading…
Reference in New Issue