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

login.go 11 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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/Unknwon/com"
  14. "github.com/go-xorm/core"
  15. "github.com/go-xorm/xorm"
  16. "github.com/gogits/gogs/modules/auth/ldap"
  17. "github.com/gogits/gogs/modules/auth/pam"
  18. "github.com/gogits/gogs/modules/log"
  19. )
  20. type LoginType int
  21. // Note: new type must be added at the end of list to maintain compatibility.
  22. const (
  23. NOTYPE LoginType = iota
  24. PLAIN
  25. LDAP
  26. SMTP
  27. PAM
  28. DLDAP
  29. )
  30. var (
  31. ErrAuthenticationAlreadyExist = errors.New("Authentication already exist")
  32. ErrAuthenticationNotExist = errors.New("Authentication does not exist")
  33. ErrAuthenticationUserUsed = errors.New("Authentication has been used by some users")
  34. )
  35. var LoginNames = map[LoginType]string{
  36. LDAP: "LDAP (via BindDN)",
  37. DLDAP: "LDAP (simple auth)",
  38. SMTP: "SMTP",
  39. PAM: "PAM",
  40. }
  41. // Ensure structs implemented interface.
  42. var (
  43. _ core.Conversion = &LDAPConfig{}
  44. _ core.Conversion = &SMTPConfig{}
  45. _ core.Conversion = &PAMConfig{}
  46. )
  47. type LDAPConfig struct {
  48. *ldap.Source
  49. }
  50. func (cfg *LDAPConfig) FromDB(bs []byte) error {
  51. return json.Unmarshal(bs, &cfg)
  52. }
  53. func (cfg *LDAPConfig) ToDB() ([]byte, error) {
  54. return json.Marshal(cfg)
  55. }
  56. type SMTPConfig struct {
  57. Auth string
  58. Host string
  59. Port int
  60. AllowedDomains string `xorm:"TEXT"`
  61. TLS bool
  62. SkipVerify bool
  63. }
  64. func (cfg *SMTPConfig) FromDB(bs []byte) error {
  65. return json.Unmarshal(bs, cfg)
  66. }
  67. func (cfg *SMTPConfig) ToDB() ([]byte, error) {
  68. return json.Marshal(cfg)
  69. }
  70. type PAMConfig struct {
  71. ServiceName string // pam service (e.g. system-auth)
  72. }
  73. func (cfg *PAMConfig) FromDB(bs []byte) error {
  74. return json.Unmarshal(bs, &cfg)
  75. }
  76. func (cfg *PAMConfig) ToDB() ([]byte, error) {
  77. return json.Marshal(cfg)
  78. }
  79. type LoginSource struct {
  80. ID int64 `xorm:"pk autoincr"`
  81. Type LoginType
  82. Name string `xorm:"UNIQUE"`
  83. IsActived bool `xorm:"NOT NULL DEFAULT false"`
  84. Cfg core.Conversion `xorm:"TEXT"`
  85. Created time.Time `xorm:"CREATED"`
  86. Updated time.Time `xorm:"UPDATED"`
  87. }
  88. func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
  89. switch colName {
  90. case "type":
  91. switch LoginType((*val).(int64)) {
  92. case LDAP, DLDAP:
  93. source.Cfg = new(LDAPConfig)
  94. case SMTP:
  95. source.Cfg = new(SMTPConfig)
  96. case PAM:
  97. source.Cfg = new(PAMConfig)
  98. default:
  99. panic("unrecognized login source type: " + com.ToStr(*val))
  100. }
  101. }
  102. }
  103. func (source *LoginSource) TypeName() string {
  104. return LoginNames[source.Type]
  105. }
  106. func (source *LoginSource) IsLDAP() bool {
  107. return source.Type == LDAP
  108. }
  109. func (source *LoginSource) IsDLDAP() bool {
  110. return source.Type == DLDAP
  111. }
  112. func (source *LoginSource) IsSMTP() bool {
  113. return source.Type == SMTP
  114. }
  115. func (source *LoginSource) IsPAM() bool {
  116. return source.Type == PAM
  117. }
  118. func (source *LoginSource) UseTLS() bool {
  119. switch source.Type {
  120. case LDAP, DLDAP:
  121. return source.LDAP().UseSSL
  122. case SMTP:
  123. return source.SMTP().TLS
  124. }
  125. return false
  126. }
  127. func (source *LoginSource) SkipVerify() bool {
  128. switch source.Type {
  129. case LDAP, DLDAP:
  130. return source.LDAP().SkipVerify
  131. case SMTP:
  132. return source.SMTP().SkipVerify
  133. }
  134. return false
  135. }
  136. func (source *LoginSource) LDAP() *LDAPConfig {
  137. return source.Cfg.(*LDAPConfig)
  138. }
  139. func (source *LoginSource) SMTP() *SMTPConfig {
  140. return source.Cfg.(*SMTPConfig)
  141. }
  142. func (source *LoginSource) PAM() *PAMConfig {
  143. return source.Cfg.(*PAMConfig)
  144. }
  145. // CountLoginSources returns number of login sources.
  146. func CountLoginSources() int64 {
  147. count, _ := x.Count(new(LoginSource))
  148. return count
  149. }
  150. func CreateSource(source *LoginSource) error {
  151. _, err := x.Insert(source)
  152. return err
  153. }
  154. func LoginSources() ([]*LoginSource, error) {
  155. auths := make([]*LoginSource, 0, 5)
  156. return auths, x.Find(&auths)
  157. }
  158. func GetLoginSourceByID(id int64) (*LoginSource, error) {
  159. source := new(LoginSource)
  160. has, err := x.Id(id).Get(source)
  161. if err != nil {
  162. return nil, err
  163. } else if !has {
  164. return nil, ErrAuthenticationNotExist
  165. }
  166. return source, nil
  167. }
  168. func UpdateSource(source *LoginSource) error {
  169. _, err := x.Id(source.ID).AllCols().Update(source)
  170. return err
  171. }
  172. func DeleteSource(source *LoginSource) error {
  173. count, err := x.Count(&User{LoginSource: source.ID})
  174. if err != nil {
  175. return err
  176. } else if count > 0 {
  177. return ErrAuthenticationUserUsed
  178. }
  179. _, err = x.Id(source.ID).Delete(new(LoginSource))
  180. return err
  181. }
  182. // .____ ________ _____ __________
  183. // | | \______ \ / _ \\______ \
  184. // | | | | \ / /_\ \| ___/
  185. // | |___ | ` \/ | \ |
  186. // |_______ \/_______ /\____|__ /____|
  187. // \/ \/ \/
  188. // LoginUserLDAPSource queries if name/passwd can login against the LDAP directory pool,
  189. // and create a local user if success when enabled.
  190. // It returns the same LoginUserPlain semantic.
  191. func LoginUserLDAPSource(u *User, name, passwd string, source *LoginSource, autoRegister bool) (*User, error) {
  192. cfg := source.Cfg.(*LDAPConfig)
  193. directBind := (source.Type == DLDAP)
  194. fn, sn, mail, admin, logged := cfg.SearchEntry(name, passwd, directBind)
  195. if !logged {
  196. // User not in LDAP, do nothing
  197. return nil, ErrUserNotExist{0, name}
  198. }
  199. if !autoRegister {
  200. return u, nil
  201. }
  202. // Fallback.
  203. if len(mail) == 0 {
  204. mail = fmt.Sprintf("%s@localhost", name)
  205. }
  206. u = &User{
  207. LowerName: strings.ToLower(name),
  208. Name: name,
  209. FullName: strings.TrimSpace(fn + " " + sn),
  210. LoginType: source.Type,
  211. LoginSource: source.ID,
  212. LoginName: name,
  213. Email: mail,
  214. IsAdmin: admin,
  215. IsActive: true,
  216. }
  217. return u, CreateUser(u)
  218. }
  219. // _________ __________________________
  220. // / _____/ / \__ ___/\______ \
  221. // \_____ \ / \ / \| | | ___/
  222. // / \/ Y \ | | |
  223. // /_______ /\____|__ /____| |____|
  224. // \/ \/
  225. type loginAuth struct {
  226. username, password string
  227. }
  228. func LoginAuth(username, password string) smtp.Auth {
  229. return &loginAuth{username, password}
  230. }
  231. func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
  232. return "LOGIN", []byte(a.username), nil
  233. }
  234. func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
  235. if more {
  236. switch string(fromServer) {
  237. case "Username:":
  238. return []byte(a.username), nil
  239. case "Password:":
  240. return []byte(a.password), nil
  241. }
  242. }
  243. return nil, nil
  244. }
  245. const (
  246. SMTP_PLAIN = "PLAIN"
  247. SMTP_LOGIN = "LOGIN"
  248. )
  249. var SMTPAuths = []string{SMTP_PLAIN, SMTP_LOGIN}
  250. func SMTPAuth(a smtp.Auth, cfg *SMTPConfig) error {
  251. c, err := smtp.Dial(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port))
  252. if err != nil {
  253. return err
  254. }
  255. defer c.Close()
  256. if err = c.Hello("gogs"); err != nil {
  257. return err
  258. }
  259. if cfg.TLS {
  260. if ok, _ := c.Extension("STARTTLS"); ok {
  261. if err = c.StartTLS(&tls.Config{
  262. InsecureSkipVerify: cfg.SkipVerify,
  263. ServerName: cfg.Host,
  264. }); err != nil {
  265. return err
  266. }
  267. } else {
  268. return errors.New("SMTP server unsupports TLS")
  269. }
  270. }
  271. if ok, _ := c.Extension("AUTH"); ok {
  272. if err = c.Auth(a); err != nil {
  273. return err
  274. }
  275. return nil
  276. }
  277. return ErrUnsupportedLoginType
  278. }
  279. // Query if name/passwd can login against the LDAP directory pool
  280. // Create a local user if success
  281. // Return the same LoginUserPlain semantic
  282. func LoginUserSMTPSource(u *User, name, passwd string, sourceId int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {
  283. // Verify allowed domains.
  284. if len(cfg.AllowedDomains) > 0 {
  285. idx := strings.Index(name, "@")
  286. if idx == -1 {
  287. return nil, ErrUserNotExist{0, name}
  288. } else if !com.IsSliceContainsStr(strings.Split(cfg.AllowedDomains, ","), name[idx+1:]) {
  289. return nil, ErrUserNotExist{0, name}
  290. }
  291. }
  292. var auth smtp.Auth
  293. if cfg.Auth == SMTP_PLAIN {
  294. auth = smtp.PlainAuth("", name, passwd, cfg.Host)
  295. } else if cfg.Auth == SMTP_LOGIN {
  296. auth = LoginAuth(name, passwd)
  297. } else {
  298. return nil, errors.New("Unsupported SMTP auth type")
  299. }
  300. if err := SMTPAuth(auth, cfg); err != nil {
  301. if strings.Contains(err.Error(), "Username and Password not accepted") {
  302. return nil, ErrUserNotExist{0, name}
  303. }
  304. return nil, err
  305. }
  306. if !autoRegister {
  307. return u, nil
  308. }
  309. var loginName = name
  310. idx := strings.Index(name, "@")
  311. if idx > -1 {
  312. loginName = name[:idx]
  313. }
  314. // fake a local user creation
  315. u = &User{
  316. LowerName: strings.ToLower(loginName),
  317. Name: strings.ToLower(loginName),
  318. LoginType: SMTP,
  319. LoginSource: sourceId,
  320. LoginName: name,
  321. IsActive: true,
  322. Passwd: passwd,
  323. Email: name,
  324. }
  325. err := CreateUser(u)
  326. return u, err
  327. }
  328. // __________ _____ _____
  329. // \______ \/ _ \ / \
  330. // | ___/ /_\ \ / \ / \
  331. // | | / | \/ Y \
  332. // |____| \____|__ /\____|__ /
  333. // \/ \/
  334. // Query if name/passwd can login against PAM
  335. // Create a local user if success
  336. // Return the same LoginUserPlain semantic
  337. func LoginUserPAMSource(u *User, name, passwd string, sourceId int64, cfg *PAMConfig, autoRegister bool) (*User, error) {
  338. if err := pam.PAMAuth(cfg.ServiceName, name, passwd); err != nil {
  339. if strings.Contains(err.Error(), "Authentication failure") {
  340. return nil, ErrUserNotExist{0, name}
  341. }
  342. return nil, err
  343. }
  344. if !autoRegister {
  345. return u, nil
  346. }
  347. // fake a local user creation
  348. u = &User{
  349. LowerName: strings.ToLower(name),
  350. Name: strings.ToLower(name),
  351. LoginType: PAM,
  352. LoginSource: sourceId,
  353. LoginName: name,
  354. IsActive: true,
  355. Passwd: passwd,
  356. Email: name,
  357. }
  358. err := CreateUser(u)
  359. return u, err
  360. }
  361. func ExternalUserLogin(u *User, name, passwd string, source *LoginSource, autoRegister bool) (*User, error) {
  362. if !source.IsActived {
  363. return nil, ErrLoginSourceNotActived
  364. }
  365. switch source.Type {
  366. case LDAP, DLDAP:
  367. return LoginUserLDAPSource(u, name, passwd, source, autoRegister)
  368. case SMTP:
  369. return LoginUserSMTPSource(u, name, passwd, source.ID, source.Cfg.(*SMTPConfig), autoRegister)
  370. case PAM:
  371. return LoginUserPAMSource(u, name, passwd, source.ID, source.Cfg.(*PAMConfig), autoRegister)
  372. }
  373. return nil, ErrUnsupportedLoginType
  374. }
  375. // UserSignIn validates user name and password.
  376. func UserSignIn(uname, passwd string) (*User, error) {
  377. var u *User
  378. if strings.Contains(uname, "@") {
  379. u = &User{Email: uname}
  380. } else {
  381. u = &User{LowerName: strings.ToLower(uname)}
  382. }
  383. userExists, err := x.Get(u)
  384. if err != nil {
  385. return nil, err
  386. }
  387. if userExists {
  388. switch u.LoginType {
  389. case NOTYPE, PLAIN:
  390. if u.ValidatePassword(passwd) {
  391. return u, nil
  392. }
  393. return nil, ErrUserNotExist{u.Id, u.Name}
  394. default:
  395. var source LoginSource
  396. hasSource, err := x.Id(u.LoginSource).Get(&source)
  397. if err != nil {
  398. return nil, err
  399. } else if !hasSource {
  400. return nil, ErrLoginSourceNotExist
  401. }
  402. return ExternalUserLogin(u, u.LoginName, passwd, &source, false)
  403. }
  404. }
  405. var sources []LoginSource
  406. if err = x.UseBool().Find(&sources, &LoginSource{IsActived: true}); err != nil {
  407. return nil, err
  408. }
  409. for _, source := range sources {
  410. u, err := ExternalUserLogin(nil, uname, passwd, &source, true)
  411. if err == nil {
  412. return u, nil
  413. }
  414. log.Warn("Failed to login '%s' via '%s': %v", uname, source.Name, err)
  415. }
  416. return nil, ErrUserNotExist{u.Id, u.Name}
  417. }