add smtp authentication
This commit is contained in:
parent
26c0113ea0
commit
b33f255c40
1 changed files with 125 additions and 4 deletions
129
models/login.go
129
models/login.go
|
@ -7,6 +7,8 @@ package models
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/smtp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -50,6 +52,22 @@ func (cfg *LDAPConfig) ToDB() ([]byte, error) {
|
||||||
return json.Marshal(cfg.Ldapsource)
|
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 {
|
type LoginSource struct {
|
||||||
Id int64
|
Id int64
|
||||||
Type int
|
Type int
|
||||||
|
@ -69,6 +87,10 @@ func (source *LoginSource) LDAP() *LDAPConfig {
|
||||||
return source.Cfg.(*LDAPConfig)
|
return source.Cfg.(*LDAPConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (source *LoginSource) SMTP() *SMTPConfig {
|
||||||
|
return source.Cfg.(*SMTPConfig)
|
||||||
|
}
|
||||||
|
|
||||||
// for xorm callback
|
// for xorm callback
|
||||||
func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
|
func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
|
||||||
if colName == "type" {
|
if colName == "type" {
|
||||||
|
@ -76,6 +98,8 @@ func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
|
||||||
switch ty {
|
switch ty {
|
||||||
case LT_LDAP:
|
case LT_LDAP:
|
||||||
source.Cfg = new(LDAPConfig)
|
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 {
|
for _, source := range sources {
|
||||||
u, err := LoginUserLdapSource(nil, u.LoginName, passwd,
|
if source.Type == LT_LDAP {
|
||||||
source.Id, source.Cfg.(*LDAPConfig), true)
|
u, err := LoginUserLdapSource(nil, u.LoginName, passwd,
|
||||||
if err == nil {
|
source.Id, source.Cfg.(*LDAPConfig), true)
|
||||||
return u, err
|
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,
|
return LoginUserLdapSource(u, u.LoginName, passwd,
|
||||||
source.Id, source.Cfg.(*LDAPConfig), false)
|
source.Id, source.Cfg.(*LDAPConfig), false)
|
||||||
case LT_SMTP:
|
case LT_SMTP:
|
||||||
|
return LoginUserSMTPSource(u, u.LoginName, passwd,
|
||||||
|
source.Id, source.Cfg.(*SMTPConfig), false)
|
||||||
}
|
}
|
||||||
return nil, ErrUnsupportedLoginType
|
return nil, ErrUnsupportedLoginType
|
||||||
}
|
}
|
||||||
|
@ -232,3 +267,89 @@ func LoginUserLdapSource(user *User, name, passwd string, sourceId int64, cfg *L
|
||||||
|
|
||||||
return RegisterUser(user)
|
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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue