package main import ( "crypto/md5" "encoding/base64" "encoding/json" "fmt" "log" "strings" "time" "github.com/474420502/perfectshutdown" "github.com/474420502/requests" arraystack "github.com/474420502/structure/stack/array" "github.com/go-ldap/ldap/v3" "github.com/tidwall/gjson" ) var appkey = "dingwzebpctav6l3bvkn" var appsecret = "M_WTqBDk06IS6maj_EHipsvYQe76Led72dTKqceHnVJELJ44KOyG1qV5O6MeX2e_" type Department struct { DepartID int64 Name string DN []string Sub []*Department 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() { pf := perfectshutdown.New() pf.Loop(func(index int, cxt *perfectshutdown.PerfectShutdown) { ldapconn, err := ldap.DialURL("ldap://ldap.yuandian.com:389") if err != nil { log.Fatal(err) } 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 { 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) 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)) } resp, err = tp.Execute() if err != nil { 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())) } if len(allperson) > 0 { if !LdapGroupAdd(ldapconn, "源典所有成员", "源典所有成员", allperson) { LdapGroupModify(ldapconn, "源典所有成员", "源典所有成员", allperson) } } cxt.Wait(time.Minute * 15) }) }