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.

370 lines
8.1 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
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 models
  5. import (
  6. "crypto/tls"
  7. "encoding/json"
  8. "errors"
  9. "fmt"
  10. "net/smtp"
  11. "strings"
  12. "time"
  13. "github.com/go-xorm/core"
  14. "github.com/go-xorm/xorm"
  15. "github.com/gogits/gogs/modules/auth/ldap"
  16. "github.com/gogits/gogs/modules/log"
  17. )
  18. // Login types.
  19. const (
  20. LT_NOTYPE = iota
  21. LT_PLAIN
  22. LT_LDAP
  23. LT_SMTP
  24. )
  25. var (
  26. ErrAuthenticationAlreadyExist = errors.New("Authentication already exist")
  27. ErrAuthenticationNotExist = errors.New("Authentication does not exist")
  28. ErrAuthenticationUserUsed = errors.New("Authentication has been used by some users")
  29. )
  30. var LoginTypes = map[int]string{
  31. LT_LDAP: "LDAP",
  32. LT_SMTP: "SMTP",
  33. }
  34. // Ensure structs implmented interface.
  35. var (
  36. _ core.Conversion = &LDAPConfig{}
  37. _ core.Conversion = &SMTPConfig{}
  38. )
  39. type LDAPConfig struct {
  40. ldap.Ldapsource
  41. }
  42. // implement
  43. func (cfg *LDAPConfig) FromDB(bs []byte) error {
  44. return json.Unmarshal(bs, &cfg.Ldapsource)
  45. }
  46. func (cfg *LDAPConfig) ToDB() ([]byte, error) {
  47. return json.Marshal(cfg.Ldapsource)
  48. }
  49. type SMTPConfig struct {
  50. Auth string
  51. Host string
  52. Port int
  53. TLS bool
  54. }
  55. // implement
  56. func (cfg *SMTPConfig) FromDB(bs []byte) error {
  57. return json.Unmarshal(bs, cfg)
  58. }
  59. func (cfg *SMTPConfig) ToDB() ([]byte, error) {
  60. return json.Marshal(cfg)
  61. }
  62. type LoginSource struct {
  63. Id int64
  64. Type int
  65. Name string `xorm:"unique"`
  66. IsActived bool `xorm:"not null default false"`
  67. Cfg core.Conversion `xorm:"TEXT"`
  68. Created time.Time `xorm:"created"`
  69. Updated time.Time `xorm:"updated"`
  70. AllowAutoRegister bool `xorm:"not null default false"`
  71. }
  72. func (source *LoginSource) TypeString() string {
  73. return LoginTypes[source.Type]
  74. }
  75. func (source *LoginSource) LDAP() *LDAPConfig {
  76. return source.Cfg.(*LDAPConfig)
  77. }
  78. func (source *LoginSource) SMTP() *SMTPConfig {
  79. return source.Cfg.(*SMTPConfig)
  80. }
  81. // for xorm callback
  82. func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
  83. if colName == "type" {
  84. ty := (*val).(int64)
  85. switch ty {
  86. case LT_LDAP:
  87. source.Cfg = new(LDAPConfig)
  88. case LT_SMTP:
  89. source.Cfg = new(SMTPConfig)
  90. }
  91. }
  92. }
  93. func GetAuths() ([]*LoginSource, error) {
  94. var auths = make([]*LoginSource, 0)
  95. err := orm.Find(&auths)
  96. return auths, err
  97. }
  98. func GetLoginSourceById(id int64) (*LoginSource, error) {
  99. source := new(LoginSource)
  100. has, err := orm.Id(id).Get(source)
  101. if err != nil {
  102. return nil, err
  103. }
  104. if !has {
  105. return nil, ErrAuthenticationNotExist
  106. }
  107. return source, nil
  108. }
  109. func AddSource(source *LoginSource) error {
  110. _, err := orm.Insert(source)
  111. return err
  112. }
  113. func UpdateSource(source *LoginSource) error {
  114. _, err := orm.Id(source.Id).AllCols().Update(source)
  115. return err
  116. }
  117. func DelLoginSource(source *LoginSource) error {
  118. cnt, err := orm.Count(&User{LoginSource: source.Id})
  119. if err != nil {
  120. return err
  121. }
  122. if cnt > 0 {
  123. return ErrAuthenticationUserUsed
  124. }
  125. _, err = orm.Id(source.Id).Delete(&LoginSource{})
  126. return err
  127. }
  128. // login a user
  129. func LoginUser(uname, passwd string) (*User, error) {
  130. var u *User
  131. if strings.Contains(uname, "@") {
  132. u = &User{Email: uname}
  133. } else {
  134. u = &User{LowerName: strings.ToLower(uname)}
  135. }
  136. has, err := orm.Get(u)
  137. if err != nil {
  138. return nil, err
  139. }
  140. if u.LoginType == LT_NOTYPE {
  141. if has {
  142. u.LoginType = LT_PLAIN
  143. }
  144. }
  145. // for plain login, user must have existed.
  146. if u.LoginType == LT_PLAIN {
  147. if !has {
  148. return nil, ErrUserNotExist
  149. }
  150. newUser := &User{Passwd: passwd, Salt: u.Salt}
  151. newUser.EncodePasswd()
  152. if u.Passwd != newUser.Passwd {
  153. return nil, ErrUserNotExist
  154. }
  155. return u, nil
  156. } else {
  157. if !has {
  158. var sources []LoginSource
  159. if err = orm.UseBool().Find(&sources,
  160. &LoginSource{IsActived: true, AllowAutoRegister: true}); err != nil {
  161. return nil, err
  162. }
  163. for _, source := range sources {
  164. if source.Type == LT_LDAP {
  165. u, err := LoginUserLdapSource(nil, uname, passwd,
  166. source.Id, source.Cfg.(*LDAPConfig), true)
  167. if err == nil {
  168. return u, nil
  169. } else {
  170. log.Warn("Fail to login(%s) by LDAP(%s): %v", uname, source.Name, err)
  171. }
  172. } else if source.Type == LT_SMTP {
  173. u, err := LoginUserSMTPSource(nil, uname, passwd,
  174. source.Id, source.Cfg.(*SMTPConfig), true)
  175. if err == nil {
  176. return u, nil
  177. } else {
  178. log.Warn("Fail to login(%s) by SMTP(%s): %v", uname, source.Name, err)
  179. }
  180. }
  181. }
  182. return nil, ErrUserNotExist
  183. }
  184. var source LoginSource
  185. hasSource, err := orm.Id(u.LoginSource).Get(&source)
  186. if err != nil {
  187. return nil, err
  188. } else if !hasSource {
  189. return nil, ErrLoginSourceNotExist
  190. } else if !source.IsActived {
  191. return nil, ErrLoginSourceNotActived
  192. }
  193. switch u.LoginType {
  194. case LT_LDAP:
  195. return LoginUserLdapSource(u, u.LoginName, passwd,
  196. source.Id, source.Cfg.(*LDAPConfig), false)
  197. case LT_SMTP:
  198. return LoginUserSMTPSource(u, u.LoginName, passwd,
  199. source.Id, source.Cfg.(*SMTPConfig), false)
  200. }
  201. return nil, ErrUnsupportedLoginType
  202. }
  203. }
  204. // Query if name/passwd can login against the LDAP direcotry pool
  205. // Create a local user if success
  206. // Return the same LoginUserPlain semantic
  207. func LoginUserLdapSource(user *User, name, passwd string, sourceId int64, cfg *LDAPConfig, autoRegister bool) (*User, error) {
  208. mail, logged := cfg.Ldapsource.SearchEntry(name, passwd)
  209. if !logged {
  210. // user not in LDAP, do nothing
  211. return nil, ErrUserNotExist
  212. }
  213. if !autoRegister {
  214. return user, nil
  215. }
  216. // fake a local user creation
  217. user = &User{
  218. LowerName: strings.ToLower(name),
  219. Name: strings.ToLower(name),
  220. LoginType: LT_LDAP,
  221. LoginSource: sourceId,
  222. LoginName: name,
  223. IsActive: true,
  224. Passwd: passwd,
  225. Email: mail,
  226. }
  227. return RegisterUser(user)
  228. }
  229. type loginAuth struct {
  230. username, password string
  231. }
  232. func LoginAuth(username, password string) smtp.Auth {
  233. return &loginAuth{username, password}
  234. }
  235. func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
  236. return "LOGIN", []byte(a.username), nil
  237. }
  238. func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
  239. if more {
  240. switch string(fromServer) {
  241. case "Username:":
  242. return []byte(a.username), nil
  243. case "Password:":
  244. return []byte(a.password), nil
  245. }
  246. }
  247. return nil, nil
  248. }
  249. var (
  250. SMTP_PLAIN = "PLAIN"
  251. SMTP_LOGIN = "LOGIN"
  252. SMTPAuths = []string{SMTP_PLAIN, SMTP_LOGIN}
  253. )
  254. func SmtpAuth(host string, port int, a smtp.Auth, useTls bool) error {
  255. c, err := smtp.Dial(fmt.Sprintf("%s:%d", host, port))
  256. if err != nil {
  257. return err
  258. }
  259. defer c.Close()
  260. if err = c.Hello("gogs"); err != nil {
  261. return err
  262. }
  263. if useTls {
  264. if ok, _ := c.Extension("STARTTLS"); ok {
  265. config := &tls.Config{ServerName: host}
  266. if err = c.StartTLS(config); err != nil {
  267. return err
  268. }
  269. } else {
  270. return errors.New("SMTP server unsupports TLS")
  271. }
  272. }
  273. if ok, _ := c.Extension("AUTH"); ok {
  274. if err = c.Auth(a); err != nil {
  275. return err
  276. }
  277. return nil
  278. } else {
  279. return ErrUnsupportedLoginType
  280. }
  281. }
  282. // Query if name/passwd can login against the LDAP direcotry pool
  283. // Create a local user if success
  284. // Return the same LoginUserPlain semantic
  285. func LoginUserSMTPSource(user *User, name, passwd string, sourceId int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {
  286. var auth smtp.Auth
  287. if cfg.Auth == SMTP_PLAIN {
  288. auth = smtp.PlainAuth("", name, passwd, cfg.Host)
  289. } else if cfg.Auth == SMTP_LOGIN {
  290. auth = LoginAuth(name, passwd)
  291. } else {
  292. return nil, errors.New("Unsupported SMTP auth type")
  293. }
  294. if err := SmtpAuth(cfg.Host, cfg.Port, auth, cfg.TLS); err != nil {
  295. if strings.Contains(err.Error(), "Username and Password not accepted") {
  296. return nil, ErrUserNotExist
  297. }
  298. return nil, err
  299. }
  300. if !autoRegister {
  301. return user, nil
  302. }
  303. var loginName = name
  304. idx := strings.Index(name, "@")
  305. if idx > -1 {
  306. loginName = name[:idx]
  307. }
  308. // fake a local user creation
  309. user = &User{
  310. LowerName: strings.ToLower(loginName),
  311. Name: strings.ToLower(loginName),
  312. LoginType: LT_SMTP,
  313. LoginSource: sourceId,
  314. LoginName: name,
  315. IsActive: true,
  316. Passwd: passwd,
  317. Email: name,
  318. }
  319. return RegisterUser(user)
  320. }