summaryrefslogtreecommitdiffstats
path: root/models/login.go
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2014-05-11 15:49:36 +0800
committerLunny Xiao <xiaolunwen@gmail.com>2014-05-11 15:49:36 +0800
commitb33f255c40d183631a085f72ad45e6ee86ba9d48 (patch)
tree4b62c09fc79ce00efe3c3ee6da3324fd5737b416 /models/login.go
parent26c0113ea0c69be52e9b02145bf811189505915a (diff)
downloadgitea-b33f255c40d183631a085f72ad45e6ee86ba9d48.tar.gz
gitea-b33f255c40d183631a085f72ad45e6ee86ba9d48.zip
add smtp authentication
Diffstat (limited to 'models/login.go')
-rw-r--r--models/login.go129
1 files changed, 125 insertions, 4 deletions
diff --git a/models/login.go b/models/login.go
index 05ffac2c57..7313726562 100644
--- a/models/login.go
+++ b/models/login.go
@@ -7,6 +7,8 @@ package models
import (
"encoding/json"
"errors"
+ "fmt"
+ "net/smtp"
"strings"
"time"
@@ -50,6 +52,22 @@ func (cfg *LDAPConfig) ToDB() ([]byte, error) {
return json.Marshal(cfg.Ldapsource)
}
+type SMTPConfig struct {
+ Auth string
+ Host string
+ Post string
+ TLS bool
+}
+
+// implement
+func (cfg *SMTPConfig) FromDB(bs []byte) error {
+ return json.Unmarshal(bs, cfg)
+}
+
+func (cfg *SMTPConfig) ToDB() ([]byte, error) {
+ return json.Marshal(cfg)
+}
+
type LoginSource struct {
Id int64
Type int
@@ -69,6 +87,10 @@ func (source *LoginSource) LDAP() *LDAPConfig {
return source.Cfg.(*LDAPConfig)
}
+func (source *LoginSource) SMTP() *SMTPConfig {
+ return source.Cfg.(*SMTPConfig)
+}
+
// for xorm callback
func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
if colName == "type" {
@@ -76,6 +98,8 @@ func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
switch ty {
case LT_LDAP:
source.Cfg = new(LDAPConfig)
+ case LT_SMTP:
+ source.Cfg = new(SMTPConfig)
}
}
}
@@ -172,10 +196,19 @@ func LoginUser(uname, passwd string) (*User, error) {
}
for _, source := range sources {
- u, err := LoginUserLdapSource(nil, u.LoginName, passwd,
- source.Id, source.Cfg.(*LDAPConfig), true)
- if err == nil {
- return u, err
+ if source.Type == LT_LDAP {
+ u, err := LoginUserLdapSource(nil, u.LoginName, passwd,
+ source.Id, source.Cfg.(*LDAPConfig), true)
+ if err == nil {
+ return u, err
+ }
+ } else if source.Type == LT_SMTP {
+ u, err := LoginUserSMTPSource(nil, u.LoginName, passwd,
+ source.Id, source.Cfg.(*SMTPConfig), true)
+
+ if err == nil {
+ return u, err
+ }
}
}
@@ -200,6 +233,8 @@ func LoginUser(uname, passwd string) (*User, error) {
return LoginUserLdapSource(u, u.LoginName, passwd,
source.Id, source.Cfg.(*LDAPConfig), false)
case LT_SMTP:
+ return LoginUserSMTPSource(u, u.LoginName, passwd,
+ source.Id, source.Cfg.(*SMTPConfig), false)
}
return nil, ErrUnsupportedLoginType
}
@@ -232,3 +267,89 @@ func LoginUserLdapSource(user *User, name, passwd string, sourceId int64, cfg *L
return RegisterUser(user)
}
+
+type loginAuth struct {
+ username, password string
+}
+
+func LoginAuth(username, password string) smtp.Auth {
+ return &loginAuth{username, password}
+}
+
+func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
+ return "LOGIN", []byte(a.username), nil
+}
+
+func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
+ if more {
+ switch string(fromServer) {
+ case "Username:":
+ return []byte(a.username), nil
+ case "Password:":
+ return []byte(a.password), nil
+ }
+ }
+ return nil, nil
+}
+
+var (
+ smtpAuths = []string{"plain", "login", ""}
+)
+
+func SmtpAuth(addr string, a smtp.Auth) error {
+ c, err := smtp.Dial(addr)
+ if err != nil {
+ return err
+ }
+ defer c.Close()
+
+ if ok, _ := c.Extension("STARTTLS"); ok {
+ if err = c.StartTLS(nil); err != nil {
+ return err
+ }
+ }
+
+ if ok, _ := c.Extension("AUTH"); ok {
+ if err = c.Auth(a); err != nil {
+ return err
+ }
+ return nil
+ } else {
+ return ErrUnsupportedLoginType
+ }
+}
+
+// Query if name/passwd can login against the LDAP direcotry pool
+// Create a local user if success
+// Return the same LoginUserPlain semantic
+func LoginUserSMTPSource(user *User, name, passwd string, sourceId int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {
+ var auth smtp.Auth
+ if cfg.Auth == "plain" {
+ auth = smtp.PlainAuth("", name, passwd, cfg.Host)
+ } else if cfg.Auth == "login" {
+ auth = LoginAuth(name, passwd)
+ }
+
+ err := SmtpAuth(fmt.Sprintf("%s:%d", cfg.Host, cfg.Post), auth)
+ if err != nil {
+ return nil, err
+ }
+
+ if !autoRegister {
+ return user, nil
+ }
+
+ // fake a local user creation
+ user = &User{
+ LowerName: strings.ToLower(name),
+ Name: strings.ToLower(name),
+ LoginType: LT_SMTP,
+ LoginSource: sourceId,
+ LoginName: name,
+ IsActive: true,
+ Passwd: passwd,
+ Email: name,
+ }
+
+ return RegisterUser(user)
+}