login.go 7.6 KB

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