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.

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