login.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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. var emailLogin bool
  127. if strings.Contains(uname, "@") {
  128. u = &User{Email: uname}
  129. emailLogin = true
  130. } else {
  131. u = &User{LowerName: strings.ToLower(uname)}
  132. }
  133. has, err := orm.Get(u)
  134. if err != nil {
  135. return nil, err
  136. }
  137. // if email login, then we cannot auto register
  138. if emailLogin {
  139. if !has {
  140. return nil, ErrUserNotExist
  141. }
  142. }
  143. if u.LoginType == LT_NOTYPE {
  144. u.LoginType = LT_PLAIN
  145. }
  146. // for plain login, user must have existed.
  147. if u.LoginType == LT_PLAIN {
  148. if !has {
  149. return nil, ErrUserNotExist
  150. }
  151. newUser := &User{Passwd: passwd, Salt: u.Salt}
  152. newUser.EncodePasswd()
  153. if u.Passwd != newUser.Passwd {
  154. return nil, ErrUserNotExist
  155. }
  156. return u, nil
  157. } else {
  158. if !has {
  159. var sources []LoginSource
  160. cond := &LoginSource{IsActived: true, AllowAutoRegisted: true}
  161. err = orm.UseBool().Find(&sources, cond)
  162. if err != nil {
  163. return nil, err
  164. }
  165. for _, source := range sources {
  166. if source.Type == LT_LDAP {
  167. u, err := LoginUserLdapSource(nil, u.LoginName, passwd,
  168. source.Id, source.Cfg.(*LDAPConfig), true)
  169. if err == nil {
  170. return u, err
  171. }
  172. } else if source.Type == LT_SMTP {
  173. u, err := LoginUserSMTPSource(nil, u.LoginName, passwd,
  174. source.Id, source.Cfg.(*SMTPConfig), true)
  175. if err == nil {
  176. return u, err
  177. }
  178. }
  179. }
  180. return nil, ErrUserNotExist
  181. }
  182. var source LoginSource
  183. hasSource, err := orm.Id(u.LoginSource).Get(&source)
  184. if err != nil {
  185. return nil, err
  186. }
  187. if !hasSource {
  188. return nil, ErrLoginSourceNotExist
  189. }
  190. 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(addr string, a smtp.Auth) error {
  255. c, err := smtp.Dial(addr)
  256. if err != nil {
  257. return err
  258. }
  259. defer c.Close()
  260. if ok, _ := c.Extension("STARTTLS"); ok {
  261. if err = c.StartTLS(nil); err != nil {
  262. return err
  263. }
  264. }
  265. if ok, _ := c.Extension("AUTH"); ok {
  266. if err = c.Auth(a); err != nil {
  267. return err
  268. }
  269. return nil
  270. } else {
  271. return ErrUnsupportedLoginType
  272. }
  273. }
  274. // Query if name/passwd can login against the LDAP direcotry pool
  275. // Create a local user if success
  276. // Return the same LoginUserPlain semantic
  277. func LoginUserSMTPSource(user *User, name, passwd string, sourceId int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {
  278. var auth smtp.Auth
  279. if cfg.Auth == SMTP_PLAIN {
  280. auth = smtp.PlainAuth("", name, passwd, cfg.Host)
  281. } else if cfg.Auth == SMTP_LOGIN {
  282. auth = LoginAuth(name, passwd)
  283. }
  284. err := SmtpAuth(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), auth)
  285. if err != nil {
  286. return nil, err
  287. }
  288. if !autoRegister {
  289. return user, nil
  290. }
  291. // fake a local user creation
  292. user = &User{
  293. LowerName: strings.ToLower(name),
  294. Name: strings.ToLower(name),
  295. LoginType: LT_SMTP,
  296. LoginSource: sourceId,
  297. LoginName: name,
  298. IsActive: true,
  299. Passwd: passwd,
  300. Email: name,
  301. }
  302. return RegisterUser(user)
  303. }