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

96 lines
2.9 KiB

10 years ago
10 years ago
10 years ago
  1. // Copyright github.com/juju2013. 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/log"
  10. goldap "github.com/juju2013/goldap"
  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. BaseDN string // Base DN
  19. Attributes string // Attribut to search
  20. Filter string // Query filter to validate entry
  21. MsAdSAFormat string // in the case of MS AD Simple Authen, the format to use (see: http://msdn.microsoft.com/en-us/library/cc223499.aspx)
  22. Enabled bool // if this source is disabled
  23. }
  24. //Global LDAP directory pool
  25. var (
  26. Authensource []Ldapsource
  27. )
  28. // Add a new source (LDAP directory) to the global pool
  29. func AddSource(name string, host string, port int, usessl bool, basedn string, attributes string, filter string, msadsaformat string) {
  30. ldaphost := Ldapsource{name, host, port, usessl, basedn, attributes, filter, msadsaformat, true}
  31. Authensource = append(Authensource, ldaphost)
  32. }
  33. //LoginUser : try to login an user to LDAP sources, return requested (attribut,true) if ok, ("",false) other wise
  34. //First match wins
  35. //Returns first attribute if exists
  36. func LoginUser(name, passwd string) (a string, r bool) {
  37. r = false
  38. for _, ls := range Authensource {
  39. a, r = ls.SearchEntry(name, passwd)
  40. if r {
  41. return
  42. }
  43. }
  44. return
  45. }
  46. // searchEntry : search an LDAP source if an entry (name, passwd) is valide and in the specific filter
  47. func (ls Ldapsource) SearchEntry(name, passwd string) (string, bool) {
  48. l, err := ldapDial(ls)
  49. if err != nil {
  50. log.Error("LDAP Connect error, %s:%v", ls.Host, err)
  51. ls.Enabled = false
  52. return "", false
  53. }
  54. defer l.Close()
  55. nx := fmt.Sprintf(ls.MsAdSAFormat, name)
  56. err = l.Bind(nx, passwd)
  57. if err != nil {
  58. log.Debug("LDAP Authan failed for %s, reason: %s", nx, err.Error())
  59. return "", false
  60. }
  61. search := goldap.NewSearchRequest(
  62. ls.BaseDN,
  63. goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
  64. fmt.Sprintf(ls.Filter, name),
  65. []string{ls.Attributes},
  66. nil)
  67. sr, err := l.Search(search)
  68. if err != nil {
  69. log.Debug("LDAP Authen OK but not in filter %s", name)
  70. return "", false
  71. }
  72. log.Debug("LDAP Authen OK: %s", name)
  73. if len(sr.Entries) > 0 {
  74. r := sr.Entries[0].GetAttributeValue(ls.Attributes)
  75. return r, true
  76. }
  77. return "", true
  78. }
  79. func ldapDial(ls Ldapsource) (*goldap.Conn, error) {
  80. if ls.UseSSL {
  81. return goldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port), nil)
  82. } else {
  83. return goldap.Dial("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port))
  84. }
  85. }