From 698a1241f403e603b9f9efd5e86aa3e533e85553 Mon Sep 17 00:00:00 2001 From: eson Date: Tue, 31 May 2022 17:52:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90:=20=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E9=92=89=E9=92=89=E5=88=B0ldap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 1 + go.sum | 2 + main.go | 255 ++++++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 184 insertions(+), 74 deletions(-) diff --git a/go.mod b/go.mod index 38d6baf..8489361 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( ) require ( + github.com/474420502/perfectshutdown v0.3.1 github.com/474420502/requests v1.22.0 github.com/474420502/structure v1.0.1 github.com/tidwall/match v1.1.1 // indirect diff --git a/go.sum b/go.sum index 23c1ff0..e47f3e1 100644 --- a/go.sum +++ b/go.sum @@ -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/requests v1.22.0 h1:dRQczuYg3K3GlaQgm8SZQLmpiKc+jlOKzN0LkAKXUAo= github.com/474420502/requests v1.22.0/go.mod h1:043PKfW//QR069XTYG5WT7t+z+d+8/C5PJtfWzpsf+o= diff --git a/main.go b/main.go index 3adceb2..4c8ef72 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,10 @@ import ( "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" @@ -24,93 +27,197 @@ type Department struct { 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() { - ldapconn, err := ldap.DialURL("ldap://ldap.yuandian.com:389") - if err != nil { - log.Fatal(err) - } - defer ldapconn.Close() + pf := perfectshutdown.New() - 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) - - 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)) + pf.Loop(func(index int, cxt *perfectshutdown.PerfectShutdown) { + ldapconn, err := ldap.DialURL("ldap://ldap.yuandian.com:389") + if err != nil { + log.Fatal(err) } - 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 { 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() - for _, sub := range listsub { - var dept = &Department{ - DepartID: sub.Get("dept_id").Int(), - Name: sub.Get("name").String(), + 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)) } - 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") - - 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) + 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())) } - log.Println(string(resp.Content())) - } + if !LdapGroupAdd(ldapconn, "源典所有成员", "源典所有成员", allperson) { + LdapGroupModify(ldapconn, "源典所有成员", "源典所有成员", allperson) + } + cxt.Wait(time.Minute * 5) + }) - log.Println(Root) }