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

1、增加用户密码随时产生8位,由大小写字母、数字、特殊字符。 2、增加添加用户时新用户名和密码通过邮箱发送给用户。 #230

Open
wants to merge 4 commits into
base: main
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
5 changes: 4 additions & 1 deletion config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ system:
rsa-public-key: go-ldap-admin-pub.pem
# rsa私钥文件路径(config.yml相对路径, 也可以填绝对路径)
rsa-private-key: go-ldap-admin-priv.pem
#定时扫描用户过期时间 90天自动将状态修改为不可用
enable-check-user: true
check-user-sync-time: "0 */1 * * * *"

logs:
# 日志等级(-1:Debug, 0:Info, 1:Warn, 2:Error, 3:DPanic, 4:Panic, 5:Fatal, -1<=level<=5, 参照zap.level源码)
Expand Down Expand Up @@ -102,7 +105,7 @@ ldap:
# ldap用户OU
user-dn: "ou=people,dc=eryajf,dc=net"
# ldap用户初始默认密码
user-init-password: "123456"
# user-init-password: "123456"
# 是否允许更改分组DN
group-name-modify: false
# 是否允许更改用户DN
Expand Down
18 changes: 10 additions & 8 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,16 @@ func RSAReadKeyFromFile(filename string) []byte {
}

type SystemConfig struct {
Mode string `mapstructure:"mode" json:"mode"`
UrlPathPrefix string `mapstructure:"url-path-prefix" json:"urlPathPrefix"`
Port int `mapstructure:"port" json:"port"`
InitData bool `mapstructure:"init-data" json:"initData"`
RSAPublicKey string `mapstructure:"rsa-public-key" json:"rsaPublicKey"`
RSAPrivateKey string `mapstructure:"rsa-private-key" json:"rsaPrivateKey"`
RSAPublicBytes []byte `mapstructure:"-" json:"-"`
RSAPrivateBytes []byte `mapstructure:"-" json:"-"`
Mode string `mapstructure:"mode" json:"mode"`
UrlPathPrefix string `mapstructure:"url-path-prefix" json:"urlPathPrefix"`
Port int `mapstructure:"port" json:"port"`
InitData bool `mapstructure:"init-data" json:"initData"`
RSAPublicKey string `mapstructure:"rsa-public-key" json:"rsaPublicKey"`
RSAPrivateKey string `mapstructure:"rsa-private-key" json:"rsaPrivateKey"`
RSAPublicBytes []byte `mapstructure:"-" json:"-"`
RSAPrivateBytes []byte `mapstructure:"-" json:"-"`
EnableCheckUser bool `mapstructure:"enable-check-user" json:"enableCheckUser"`
CheckUserSyncTime string `mapstructure:"check-user-sync-time" json:"checkUserSyncTime"`
}

type LogsConfig struct {
Expand Down
9 changes: 9 additions & 0 deletions logic/a_logic.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,15 @@ func ConvertUserData(flag string, remoteData []map[string]interface{}) (users []
func InitCron() {
c := cron.New(cron.WithSeconds())

if config.Conf.System.EnableCheckUser {
_, err := c.AddFunc(config.Conf.System.CheckUserSyncTime, func() {
User.CheckUserTime(nil, nil)
})
if err != nil {
common.Log.Errorf("eteststset: %v", err)
}
}

if config.Conf.DingTalk.EnableSync {
//启动定时任务
_, err := c.AddFunc(config.Conf.DingTalk.DeptSyncTime, func() {
Expand Down
77 changes: 76 additions & 1 deletion logic/user_logic.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package logic

import (
"fmt"
"time"

"github.com/eryajf/go-ldap-admin/config"
"github.com/eryajf/go-ldap-admin/model"
Expand Down Expand Up @@ -50,7 +51,10 @@ func (l UserLogic) Add(c *gin.Context, req interface{}) (data interface{}, rspEr
return nil, tools.NewValidatorError(fmt.Errorf("密码长度至少为6位"))
}
} else {
r.Password = config.Conf.Ldap.UserInitPassword
//取消默认密码为123456 改为随时生成8位
//r.Password = config.Conf.Ldap.UserInitPassword
r.Password = tools.GenerateRandomPassword()

}

// 当前登陆用户角色排序最小值(最高等级角色)以及当前登陆的用户
Expand Down Expand Up @@ -118,6 +122,13 @@ func (l UserLogic) Add(c *gin.Context, req interface{}) (data interface{}, rspEr
if err != nil {
return nil, tools.NewOperationError(fmt.Errorf("添加用户失败" + err.Error()))
}

//用户注册成功后通过邮件发送
err = tools.SendResigtryMail([]string{user.Mail}, user.Username, r.Password)
if err != nil {
return nil, tools.NewLdapError(fmt.Errorf("注册用户邮件发送失败" + err.Error()))
}

return nil, nil
}

Expand Down Expand Up @@ -400,6 +411,24 @@ func (l UserLogic) ChangeUserStatus(c *gin.Context, req interface{}) (data inter
if err != nil {
return nil, tools.NewLdapError(fmt.Errorf("在LDAP添加用户失败" + err.Error()))
}

//修复,当用户状态为离职时,定时任务会将ldap用户同步sql,发现用户已离职并且ldap已删除,会将sql中同步状态设置为2
//再次将用户状态设置为在职时,信息会再次从sql同步至ldap,但同步状态依然为2,点击同步时会提示用户已存在。
//将离职人员再次设置为在职时,先查询用户是否被正常创建,如创建成功则将同步状态修改为1(已同步)
filter := map[string]interface{}{
"uid": user.Username,
}
exist, err := ildap.User.Exist(filter)
if err != nil {
return nil, tools.NewLdapError(fmt.Errorf("查询用户失败" + err.Error()))
}

if exist {
isql.User.ChangeSyncState(int(r.ID), 1)
} else {
return nil, tools.NewLdapError(fmt.Errorf("用户不存在" + err.Error()))
}

}
err = isql.User.ChangeStatus(int(r.ID), int(r.Status))
if err != nil {
Expand All @@ -424,3 +453,49 @@ func (l UserLogic) GetUserInfo(c *gin.Context, req interface{}) (data interface{
}
return user, nil
}

// 检查用户时间,超过90天禁用账号。提前15天邮件通知
func (l UserLogic) CheckUserTime(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {

//获取所有用户信息
users, err := isql.User.ListAll()
if err != nil {
return nil, tools.NewMySqlError(fmt.Errorf("获取用户列表失败:" + err.Error()))
}

for _, user := range users {
//当前时间
currentTime := time.Now()
//用户更新时间转换成时间戳
updatetimestamp := tools.ConvertToTimestamp(user.UpdatedAt)
//当前时间转换成时间戳
nowtimestamp := tools.ConvertToTimestamp(currentTime)
//计算更新时间与当前时间差值,大于75邮件通知
days := tools.CalculateDaysBetweenTimestamps(updatetimestamp, nowtimestamp)
//排除dev-jeknis-git、admin两个用户的检查
if user.Username != "dev-jenkins-git" && user.Username != "admin" && user.Status != 2 {
if days >= 75 {
err = tools.SendCheckUserMail([]string{user.Mail}, user.Username, int(days))
if err != nil {
return nil, tools.NewLdapError(fmt.Errorf("检查用户密码过期邮件发送失败" + err.Error()))
}
}

//大于91天则将账号设置为离职状态
if days > 91 {
//修改用户状态为2,离职
err = isql.User.ChangeStatus(int(user.ID), 2)
if err != nil {
return nil, tools.NewMySqlError(fmt.Errorf("获取用户列表失败:" + err.Error()))
}
//并同步删除ldap用户信息
err = ildap.User.Delete(user.UserDN)
if err != nil {
return nil, tools.NewLdapError(fmt.Errorf("在LDAP删除用户失败" + err.Error()))
}
}
}

}
return nil, nil
}
35 changes: 35 additions & 0 deletions public/tools/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,41 @@ func email(mailTo []string, subject string, body string) error {
return do.DialAndSend(newmail)
}

func SendResigtryMail(sendto []string, user string, passwd string) error {
subject := "新注册用户"
body := fmt.Sprintf(`<div>
<div>
尊敬的用户 %s ,您好!
</div>
<div style="padding: 8px 40px 8px 50px;">
<p>你注册的用户密码为: %s ,为了保证账号安全,切勿向他人泄露,感谢您的理解与使用。</p>
</div>
<div>
<p>此邮箱为系统邮箱,请勿回复。</p>
</div>
</div>`, user, passwd)
return email(sendto, subject, body)

}

// 发送检查用户更新密码时间
func SendCheckUserMail(sendto []string, user string, day int) error {
subject := "用户过期"
body := fmt.Sprintf(`<div>
<div>
尊敬的用户: %s ,您好!
</div>
<div style="padding: 8px 40px 8px 50px;">
<p>你的用户密码将于 %d 后到期, 为不影响正常使用,请及时修改密码。</p>
</div>
<div>
<p>此邮箱为系统邮箱,请勿回复。</p>
</div>
</div>`, user, day)
return email(sendto, subject, body)

}

func SendMail(sendto []string, pass string) error {
subject := "重置LDAP密码成功"
// 邮件正文
Expand Down
23 changes: 23 additions & 0 deletions public/tools/randpass.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tools

import (
"crypto/rand"
"math/big"
)

const (
passwordLength = 8
letters = "abcdefghijklmnopqrstu@vwxyzABCDEFGHIJKL#MNOP*QRSTUVWXYZ0123456789"
lettersLength = len(letters)
)

func GenerateRandomPassword() string {
password := make([]byte, passwordLength)

for i := range password {
index, _ := rand.Int(rand.Reader, big.NewInt(int64(lettersLength)))
password[i] = letters[index.Int64()]
}

return string(password)
}
17 changes: 17 additions & 0 deletions public/tools/time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package tools

import "time"

func ConvertToTimestamp(t time.Time) int64 {
timestamp := t.Unix()
return timestamp
}

func CalculateDaysBetweenTimestamps(timestamp1, timestamp2 int64) int {
t1 := time.Unix(timestamp1, 0)
t2 := time.Unix(timestamp2, 0)

duration := t2.Sub(t1)
days := int(duration.Hours() / 24)
return days
}
6 changes: 5 additions & 1 deletion service/ildap/user_ildap.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ func (x UserService) NewPwd(username string) (string, error) {
if username == "admin" {
udn = config.Conf.Ldap.AdminDN
}
modifyPass := ldap.NewPasswordModifyRequest(udn, "", "")
//默认产生8位随机密码,不符合公司规范,故生成16位随机密码
newPasswd := tools.GenerateRandomPassword()
modifyPass := ldap.NewPasswordModifyRequest(udn, "", newPasswd)

// 获取 LDAP 连接
conn, err := common.GetLDAPConn()
Expand All @@ -156,6 +158,8 @@ func (x UserService) NewPwd(username string) (string, error) {
if err != nil {
return "", fmt.Errorf("password modify failed for %s, err: %v", username, err)
}

newpass.GeneratedPassword = newPasswd
return newpass.GeneratedPassword, nil
}
func (x UserService) ListUserDN() (users []*model.User, err error) {
Expand Down