Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加ldap用户支持otp验证 #349

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions server/admin/api_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,10 @@ func userAccountMail(user *dbdata.User) error {
DisableOtp: user.DisableOtp,
}

if user.Type == "ldap" {
data.PinCode = "同ldap密码"
}

if user.LimitTime == nil {
data.LimitTime = "无限制"
} else {
Expand Down
3 changes: 3 additions & 0 deletions server/dbdata/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ func SetGroup(g *Group) error {
if err != nil {
return err
}
if err := auth.saveUsers(g); err != nil {
return fmt.Errorf("保存ldap用户 %s 失败", err.Error())
}
// 重置Auth, 删除多余的key
g.Auth = map[string]interface{}{
"type": authType,
Expand Down
1 change: 1 addition & 0 deletions server/dbdata/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Group struct {

type User struct {
Id int `json:"id" xorm:"pk autoincr not null"`
Type string `json:"type" xorm:"varchar(20) default('local')"`
Username string `json:"username" xorm:"varchar(60) not null unique"`
Nickname string `json:"nickname" xorm:"varchar(255)"`
Email string `json:"email" xorm:"varchar(255)"`
Expand Down
6 changes: 3 additions & 3 deletions server/dbdata/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func CheckUser(name, pwd, group string, ext map[string]interface{}) error {
authType := groupData.Auth["type"].(string)
// 本地认证方式
if authType == "local" {
return checkLocalUser(name, pwd, group, ext)
return checkLocalUser(name, pwd, group)
}
// 其它认证方式, 支持自定义
_, ok := authRegistry[authType]
Expand All @@ -96,7 +96,7 @@ func CheckUser(name, pwd, group string, ext map[string]interface{}) error {
}

// 验证本地用户登录信息
func checkLocalUser(name, pwd, group string, ext map[string]interface{}) error {
func checkLocalUser(name, pwd, group string) error {
// TODO 严重问题
// return nil

Expand All @@ -120,7 +120,7 @@ func checkLocalUser(name, pwd, group string, ext map[string]interface{}) error {
}

pinCode := pwd
if base.Cfg.AuthAloneOtp == false {
if !base.Cfg.AuthAloneOtp {
// 判断otp信息
if !v.DisableOtp {
pinCode = pwd[:pl-6]
Expand Down
1 change: 1 addition & 0 deletions server/dbdata/userauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var authRegistry = make(map[string]reflect.Type)
type IUserAuth interface {
checkData(authData map[string]interface{}) error
checkUser(name, pwd string, g *Group, ext map[string]interface{}) error
saveUsers(g *Group) error
}

func makeInstance(name string) interface{} {
Expand Down
127 changes: 108 additions & 19 deletions server/dbdata/userauth_ldap.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (
"strconv"
"time"

"github.com/bjdgyc/anylink/base"
"github.com/go-ldap/ldap"
"github.com/xlzd/gotp"
)

type AuthLdap struct {
Expand All @@ -23,12 +25,115 @@ type AuthLdap struct {
ObjectClass string `json:"object_class"`
SearchAttr string `json:"search_attr"`
MemberOf string `json:"member_of"`
EnableOTP bool `json:"enable_otp"`
}

func init() {
authRegistry["ldap"] = reflect.TypeOf(AuthLdap{})
}

// 建立 LDAP 连接
func (auth AuthLdap) connect() (*ldap.Conn, error) {
// 检测服务器和端口的可用性
con, err := net.DialTimeout("tcp", auth.Addr, 3*time.Second)
if err != nil {
return nil, fmt.Errorf("LDAP服务器连接异常, 请检测服务器和端口: %s", err.Error())
}
con.Close()

// 连接LDAP
l, err := ldap.Dial("tcp", auth.Addr)
if err != nil {
return nil, fmt.Errorf("LDAP连接失败 %s %s", auth.Addr, err.Error())
}

if auth.Tls {
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
if err != nil {
return nil, fmt.Errorf("LDAP TLS连接失败 %s", err.Error())
}
}

err = l.Bind(auth.BindName, auth.BindPwd)
if err != nil {
return nil, fmt.Errorf("LDAP 管理员 DN或密码填写有误 %s", err.Error())
}

return l, nil
}

func (auth AuthLdap) saveUsers(g *Group) error {
authType := g.Auth["type"].(string)
bodyBytes, err := json.Marshal(g.Auth[authType])
if err != nil {
return errors.New("LDAP配置填写有误")
}
json.Unmarshal(bodyBytes, &auth)
l, err := auth.connect()
if err != nil {
return err
}
defer l.Close()

if auth.ObjectClass == "" {
auth.ObjectClass = "person"
}
filterAttr := "(objectClass=" + auth.ObjectClass + ")"
filterAttr += "(" + auth.SearchAttr + "=*)"
if auth.MemberOf != "" {
filterAttr += "(memberOf:=" + auth.MemberOf + ")"
}
searchRequest := ldap.NewSearchRequest(
auth.BaseDn,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf("(&%s)", filterAttr),
[]string{},
nil,
)

sr, err := l.Search(searchRequest)
if err != nil {
return fmt.Errorf("LDAP 查询失败 %s %s %s", auth.BaseDn, filterAttr, err.Error())
}
for _, entry := range sr.Entries {
var groups []string
ldapuser := &User{
Type: "ldap",
Username: entry.GetAttributeValue(auth.SearchAttr),
Nickname: entry.GetAttributeValue("displayName"),
Email: entry.GetAttributeValue("mail"),
Groups: append(groups, g.Name),
DisableOtp: !auth.EnableOTP,
OtpSecret: gotp.RandomSecret(32),
SendEmail: false,
Status: 1,
}
// 新增ldap用户
u := &User{}
if err := One("username", ldapuser.Username, u); err != nil {
if CheckErrNotFound(err) {
if err := Add(ldapuser); err != nil {
base.Error("新增ldap用户失败", ldapuser.Username, err)
continue
}
}
continue
}
if u.Type != "ldap" {
base.Warn("已存在本地同名用户:", ldapuser.Username)
continue
}
// ldap OTP全局开关
if u.DisableOtp != !auth.EnableOTP {
u.DisableOtp = !auth.EnableOTP
if err := Set(u); err != nil {
return fmt.Errorf("更新ldap用户%sOTP状态失败:%v", u.Username, err.Error())
}
}
}
return nil
}

func (auth AuthLdap) checkData(authData map[string]interface{}) error {
authType := authData["type"].(string)
bodyBytes, err := json.Marshal(authData[authType])
Expand Down Expand Up @@ -78,28 +183,12 @@ func (auth AuthLdap) checkUser(name, pwd string, g *Group, ext map[string]interf
if err != nil {
return fmt.Errorf("%s %s", name, "LDAP Unmarshal出现错误")
}
// 检测服务器和端口的可用性
con, err := net.DialTimeout("tcp", auth.Addr, 3*time.Second)
if err != nil {
return fmt.Errorf("%s %s", name, "LDAP服务器连接异常, 请检测服务器和端口")
}
defer con.Close()
// 连接LDAP
l, err := ldap.Dial("tcp", auth.Addr)
l, err := auth.connect()
if err != nil {
return fmt.Errorf("LDAP连接失败 %s %s", auth.Addr, err.Error())
return err
}
defer l.Close()
if auth.Tls {
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
if err != nil {
return fmt.Errorf("%s LDAP TLS连接失败 %s", name, err.Error())
}
}
err = l.Bind(auth.BindName, auth.BindPwd)
if err != nil {
return fmt.Errorf("%s LDAP 管理员 DN或密码填写有误 %s", name, err.Error())
}

if auth.ObjectClass == "" {
auth.ObjectClass = "person"
}
Expand Down
10 changes: 10 additions & 0 deletions server/dbdata/userauth_radius.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ type AuthRadius struct {
func init() {
authRegistry["radius"] = reflect.TypeOf(AuthRadius{})
}
func (auth AuthRadius) saveUsers(g *Group) error {
// To Do!!!
authType := g.Auth["type"].(string)
bodyBytes, err := json.Marshal(g.Auth[authType])
if err != nil {
return errors.New("Radius配置填写有误")
}
json.Unmarshal(bodyBytes, &auth)
return nil
}

func (auth AuthRadius) checkData(authData map[string]interface{}) error {
authType := authData["type"].(string)
Expand Down
Loading
Loading