完成: 定时同步钉钉到ldap

This commit is contained in:
eson 2022-05-31 17:52:43 +08:00
parent 2cad522ef5
commit 698a1241f4
3 changed files with 184 additions and 74 deletions

1
go.mod
View File

@ -14,6 +14,7 @@ require (
) )
require ( require (
github.com/474420502/perfectshutdown v0.3.1
github.com/474420502/requests v1.22.0 github.com/474420502/requests v1.22.0
github.com/474420502/structure v1.0.1 github.com/474420502/structure v1.0.1
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/match v1.1.1 // indirect

2
go.sum
View File

@ -1,3 +1,5 @@
github.com/474420502/perfectshutdown v0.3.1 h1:HFWr5pfcKOHnEe39B5PFKw2ipHCr3jKDPEvuTFMHqeo=
github.com/474420502/perfectshutdown v0.3.1/go.mod h1:qonD0eLCz1ncQq8heGQHbPdLlh30lofF2ISzV5ASW8A=
github.com/474420502/random v0.5.2-0.20220222044003-09d6ed40ca23 h1:ZO9oDeD8EOHiHbFLPlZ5WyfF0uBoYfRD0/NoEIFUeAQ= github.com/474420502/random v0.5.2-0.20220222044003-09d6ed40ca23 h1:ZO9oDeD8EOHiHbFLPlZ5WyfF0uBoYfRD0/NoEIFUeAQ=
github.com/474420502/requests v1.22.0 h1:dRQczuYg3K3GlaQgm8SZQLmpiKc+jlOKzN0LkAKXUAo= github.com/474420502/requests v1.22.0 h1:dRQczuYg3K3GlaQgm8SZQLmpiKc+jlOKzN0LkAKXUAo=
github.com/474420502/requests v1.22.0/go.mod h1:043PKfW//QR069XTYG5WT7t+z+d+8/C5PJtfWzpsf+o= github.com/474420502/requests v1.22.0/go.mod h1:043PKfW//QR069XTYG5WT7t+z+d+8/C5PJtfWzpsf+o=

255
main.go
View File

@ -6,7 +6,10 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log" "log"
"strings"
"time"
"github.com/474420502/perfectshutdown"
"github.com/474420502/requests" "github.com/474420502/requests"
arraystack "github.com/474420502/structure/stack/array" arraystack "github.com/474420502/structure/stack/array"
"github.com/go-ldap/ldap/v3" "github.com/go-ldap/ldap/v3"
@ -24,93 +27,197 @@ type Department struct {
Member gjson.Result Member gjson.Result
} }
func LdapMemberAdd(ldapconn *ldap.Conn, dn, name, title, mail, mobile string) bool {
req := ldap.NewAddRequest(strings.ReplaceAll(dn, "+", "\\+"), nil)
req.Attribute("objectClass", []string{"inetOrgPerson", "organizationalPerson", "person", "top"})
req.Attribute("cn", []string{name})
req.Attribute("sn", []string{name})
req.Attribute("displayName", []string{name})
req.Attribute("givenName", []string{name})
req.Attribute("title", []string{title})
req.Attribute("mail", []string{mail})
req.Attribute("telephoneNumber", []string{mobile})
md5hash := md5.New()
md5hash.Write([]byte(mobile))
pwd := base64.StdEncoding.EncodeToString(md5hash.Sum(nil))
req.Attribute("userPassword", []string{"{MD5}" + pwd})
err := ldapconn.Add(req)
if err != nil {
if ldap.IsErrorAnyOf(err, 68) {
return false
}
log.Panic(err)
}
return true
}
func LdapMemberModify(ldapconn *ldap.Conn, dn, name, title, mail, mobile string) bool {
req := ldap.NewModifyRequest(strings.ReplaceAll(dn, "+", "\\+"), nil)
req.Replace("objectClass", []string{"inetOrgPerson", "organizationalPerson", "person", "top"})
req.Replace("cn", []string{name})
req.Replace("sn", []string{name})
req.Replace("displayName", []string{name})
req.Replace("givenName", []string{name})
req.Replace("title", []string{title})
req.Replace("mail", []string{mail})
req.Replace("telephoneNumber", []string{mobile})
md5hash := md5.New()
md5hash.Write([]byte(mobile))
pwd := base64.StdEncoding.EncodeToString(md5hash.Sum(nil))
req.Replace("userPassword", []string{"{MD5}" + pwd})
err := ldapconn.Modify(req)
if err != nil {
log.Panic(err)
}
return true
}
func LdapGroupAdd(ldapconn *ldap.Conn, cn, description string, uniqueMember []string) bool {
// 建 组织 ou=groups,dc=yuandian,dc=com
req := ldap.NewAddRequest(fmt.Sprintf("cn=%s,ou=groups,dc=yuandian,dc=com", strings.ReplaceAll(cn, "+", "\\+")), nil)
req.Attribute("objectClass", []string{"groupOfUniqueNames", "top"})
req.Attribute("ou", []string{cn})
req.Attribute("cn", []string{cn})
req.Attribute("uniqueMember", uniqueMember)
req.Attribute("description", []string{description})
err := ldapconn.Add(req)
if err != nil {
if ldap.IsErrorAnyOf(err, 68) {
return false
}
log.Panic(err)
}
return true
}
func LdapGroupModify(ldapconn *ldap.Conn, cn, description string, uniqueMember []string) {
// 建 组织 ou=groups,dc=yuandian,dc=com
req := ldap.NewModifyRequest(fmt.Sprintf("cn=%s,ou=groups,dc=yuandian,dc=com", strings.ReplaceAll(cn, "+", "\\+")), nil)
req.Replace("objectClass", []string{"groupOfUniqueNames", "top"})
req.Replace("ou", []string{cn})
req.Replace("cn", []string{cn})
req.Replace("uniqueMember", uniqueMember)
req.Replace("description", []string{description})
err := ldapconn.Modify(req)
if err != nil {
log.Panic(err)
}
}
func main() { func main() {
ldapconn, err := ldap.DialURL("ldap://ldap.yuandian.com:389") pf := perfectshutdown.New()
if err != nil {
log.Fatal(err)
}
defer ldapconn.Close()
err = ldapconn.Bind("cn=admin,dc=yuandian,dc=com", "yuandianldap123") pf.Loop(func(index int, cxt *perfectshutdown.PerfectShutdown) {
if err != nil { ldapconn, err := ldap.DialURL("ldap://ldap.yuandian.com:389")
log.Fatal(err) if err != nil {
} log.Fatal(err)
ses := requests.NewSession()
tp := ses.Get(fmt.Sprintf("https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s", appkey, appsecret))
resp, err := tp.Execute()
if err != nil {
panic(err)
}
var rjson map[string]any
if err := json.Unmarshal(resp.Content(), &rjson); err != nil {
panic(err)
}
token := rjson["access_token"]
log.Println(token)
Root := &Department{DepartID: 1, DN: []string{"dn=yuandian", "dn=com"}}
stack := arraystack.New[*Department]()
stack.Push(Root)
for !stack.Empty() {
department, _ := stack.Pop()
// 获取子部门信息
tp = ses.Post(fmt.Sprintf("https://oapi.dingtalk.com/topapi/v2/department/listsub?access_token=%s", token))
if department.DepartID > 1 {
tp.SetBodyAuto(fmt.Sprintf(`{"dept_id": %d}`, department.DepartID))
} }
resp, err = tp.Execute() defer ldapconn.Close()
err = ldapconn.Bind("cn=admin,dc=yuandian,dc=com", "yuandianldap123")
if err != nil {
log.Fatal(err)
}
ses := requests.NewSession()
tp := ses.Get(fmt.Sprintf("https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s", appkey, appsecret))
resp, err := tp.Execute()
if err != nil { if err != nil {
panic(err) panic(err)
} }
var rjson map[string]any
if err := json.Unmarshal(resp.Content(), &rjson); err != nil {
panic(err)
}
token := rjson["access_token"]
log.Println(token)
listsub := gjson.ParseBytes(resp.Content()).Get("result").Array() Root := &Department{DepartID: 1, DN: []string{"dn=yuandian", "dn=com"}}
for _, sub := range listsub {
var dept = &Department{ stack := arraystack.New[*Department]()
DepartID: sub.Get("dept_id").Int(), stack.Push(Root)
Name: sub.Get("name").String(),
var persondict map[string]bool = make(map[string]bool)
var allperson []string
for !stack.Empty() {
department, _ := stack.Pop()
// 获取子部门信息
tp = ses.Post(fmt.Sprintf("https://oapi.dingtalk.com/topapi/v2/department/listsub?access_token=%s", token))
if department.DepartID > 1 {
tp.SetBodyAuto(fmt.Sprintf(`{"dept_id": %d}`, department.DepartID))
} }
stack.Push(dept) resp, err = tp.Execute()
department.Sub = append(department.Sub, dept)
}
tp = ses.Post(fmt.Sprintf("https://oapi.dingtalk.com/topapi/v2/user/list?access_token=%s", token))
tp.SetBodyAuto(fmt.Sprintf(`{"dept_id": %d, "cursor": 0, "size": 100}`, department.DepartID))
resp, err = tp.Execute()
if err != nil {
panic(err)
}
department.Member = gjson.ParseBytes(resp.Content()).Get("result.list")
if department.DepartID > 1 {
req := ldap.NewAddRequest("cn=haha", nil)
req.Attribute("objectClass", []string{"inetOrgPerson", "organizationalPerson", "person", "top"})
req.Attribute("cn", []string{"haha"})
req.Attribute("sn", []string{"eson"})
req.Attribute("displayName", []string{"haha"})
req.Attribute("givenName", []string{"haha"})
req.Attribute("mail", []string{"haha"})
req.Attribute("telephoneNumber", []string{"18588505404"})
md5hash := md5.New()
md5hash.Write([]byte("18588505404"))
pwd := base64.StdEncoding.EncodeToString(md5hash.Sum(nil))
log.Println(pwd)
req.Attribute("userPassword", []string{"{MD5}" + pwd})
err = ldapconn.Add(req)
if err != nil { if err != nil {
panic(err) panic(err)
} }
listsub := gjson.ParseBytes(resp.Content()).Get("result").Array()
for _, sub := range listsub {
var dept = &Department{
DepartID: sub.Get("dept_id").Int(),
Name: sub.Get("name").String(),
}
stack.Push(dept)
department.Sub = append(department.Sub, dept)
}
tp = ses.Post(fmt.Sprintf("https://oapi.dingtalk.com/topapi/v2/user/list?access_token=%s", token))
tp.SetBodyAuto(fmt.Sprintf(`{"dept_id": %d, "cursor": 0, "size": 100}`, department.DepartID))
resp, err = tp.Execute()
if err != nil {
panic(err)
}
department.Member = gjson.ParseBytes(resp.Content()).Get("result.list")
var dnmembers []string
// 建人
for _, person := range department.Member.Array() {
name := person.Get("name").String()
mail := person.Get("mail").String()
mobile := person.Get("mobile").String()
title := person.Get("title").String()
if title == "" {
title = "未设"
}
dn := fmt.Sprintf("cn=%s,ou=members,dc=yuandian,dc=com", name)
if !LdapMemberAdd(ldapconn, dn, name, title, mail, mobile) {
LdapMemberModify(ldapconn, dn, name, title, mail, mobile)
}
dnmembers = append(dnmembers, dn)
if _, ok := persondict[dn]; !ok {
allperson = append(allperson, dn)
persondict[dn] = true
}
}
if department.DepartID > 1 {
if len(dnmembers) > 0 {
if !LdapGroupAdd(ldapconn, department.Name, department.Name, dnmembers) {
LdapGroupModify(ldapconn, department.Name, department.Name, dnmembers)
}
}
}
log.Println(string(resp.Content()))
} }
log.Println(string(resp.Content())) if !LdapGroupAdd(ldapconn, "源典所有成员", "源典所有成员", allperson) {
} LdapGroupModify(ldapconn, "源典所有成员", "源典所有成员", allperson)
}
cxt.Wait(time.Minute * 5)
})
log.Println(Root)
} }