You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

ldap.go 4.1 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. // Package ldap provide functions & structure to query a LDAP ldap directory
  5. // For now, it's mainly tested again an MS Active Directory service, see README.md for more information
  6. package ldap
  7. import (
  8. "fmt"
  9. "github.com/gogits/gogs/modules/ldap"
  10. "github.com/gogits/gogs/modules/log"
  11. )
  12. // Basic LDAP authentication service
  13. type Ldapsource struct {
  14. Name string // canonical name (ie. corporate.ad)
  15. Host string // LDAP host
  16. Port int // port number
  17. UseSSL bool // Use SSL
  18. BindDN string // DN to bind with
  19. BindPassword string // Bind DN password
  20. UserBase string // Base search path for users
  21. AttributeName string // First name attribute
  22. AttributeSurname string // Surname attribute
  23. AttributeMail string // E-mail attribute
  24. Filter string // Query filter to validate entry
  25. Enabled bool // if this source is disabled
  26. }
  27. func (ls Ldapsource) FindUserDN(name string) (string, bool) {
  28. l, err := ldapDial(ls)
  29. if err != nil {
  30. log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
  31. ls.Enabled = false
  32. return "", false
  33. }
  34. defer l.Close()
  35. log.Trace("Search for LDAP user: %s", name)
  36. if ls.BindDN != "" && ls.BindPassword != "" {
  37. err = l.Bind(ls.BindDN, ls.BindPassword)
  38. if err != nil {
  39. log.Debug("Failed to bind as BindDN: %s, %s", ls.BindDN, err.Error())
  40. return "", false
  41. }
  42. log.Trace("Bound as BindDN %s", ls.BindDN)
  43. } else {
  44. log.Trace("Proceeding with anonymous LDAP search.")
  45. }
  46. // A search for the user.
  47. userFilter := fmt.Sprintf(ls.Filter, name)
  48. log.Trace("Searching using filter %s", userFilter)
  49. search := ldap.NewSearchRequest(
  50. ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0,
  51. false, userFilter, []string{}, nil)
  52. // Ensure we found a user
  53. sr, err := l.Search(search)
  54. if err != nil || len(sr.Entries) < 1 {
  55. log.Debug("Failed search using filter %s: %s", userFilter, err.Error())
  56. return "", false
  57. } else if len(sr.Entries) > 1 {
  58. log.Debug("Filter '%s' returned more than one user.", userFilter)
  59. return "", false
  60. }
  61. userDN := sr.Entries[0].DN
  62. if userDN == "" {
  63. log.Error(4, "LDAP search was succesful, but found no DN!")
  64. return "", false
  65. }
  66. return userDN, true
  67. }
  68. // searchEntry : search an LDAP source if an entry (name, passwd) is valid and in the specific filter
  69. func (ls Ldapsource) SearchEntry(name, passwd string) (string, string, string, bool) {
  70. userDN, found := ls.FindUserDN(name)
  71. if !found {
  72. return "", "", "", false
  73. }
  74. l, err := ldapDial(ls)
  75. if err != nil {
  76. log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
  77. ls.Enabled = false
  78. return "", "", "", false
  79. }
  80. defer l.Close()
  81. log.Trace("Binding with userDN: %s", userDN)
  82. err = l.Bind(userDN, passwd)
  83. if err != nil {
  84. log.Debug("LDAP auth. failed for %s, reason: %s", userDN, err.Error())
  85. return "", "", "", false
  86. }
  87. log.Trace("Bound successfully with userDN: %s", userDN)
  88. userFilter := fmt.Sprintf(ls.Filter, name)
  89. search := ldap.NewSearchRequest(
  90. userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
  91. []string{ls.AttributeName, ls.AttributeSurname, ls.AttributeMail},
  92. nil)
  93. sr, err := l.Search(search)
  94. if err != nil {
  95. log.Error(4, "LDAP Search failed unexpectedly! (%s)", err.Error())
  96. return "", "", "", false
  97. } else if len(sr.Entries) < 1 {
  98. log.Error(4, "LDAP Search failed unexpectedly! (0 entries)")
  99. return "", "", "", false
  100. }
  101. name_attr := sr.Entries[0].GetAttributeValue(ls.AttributeName)
  102. sn_attr := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
  103. mail_attr := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
  104. return name_attr, sn_attr, mail_attr, true
  105. }
  106. func ldapDial(ls Ldapsource) (*ldap.Conn, error) {
  107. if ls.UseSSL {
  108. log.Debug("Using TLS for LDAP")
  109. return ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port), nil)
  110. } else {
  111. return ldap.Dial("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port))
  112. }
  113. }