Browse Source

#1542 A way to skip TLS verify for SMTP authentication

tags/v0.9.99
Unknwon 8 years ago
parent
commit
ea454c21f7

+ 1
- 0
conf/locale/locale_en-US.ini View File

auths.smtphost = SMTP Host auths.smtphost = SMTP Host
auths.smtpport = SMTP Port auths.smtpport = SMTP Port
auths.enable_tls = Enable TLS Encryption auths.enable_tls = Enable TLS Encryption
auths.skip_tls_verify = Skip TLS Verify
auths.pam_service_name = PAM Service Name auths.pam_service_name = PAM Service Name
auths.enable_auto_register = Enable Auto Registration auths.enable_auto_register = Enable Auto Registration
auths.tips = Tips auths.tips = Tips

+ 45
- 40
models/login.go View File

} }


type SMTPConfig struct { type SMTPConfig struct {
Auth string
Host string
Port int
TLS bool
Auth string
Host string
Port int
TLS bool
SkipVerify bool
} }


func (cfg *SMTPConfig) FromDB(bs []byte) error { func (cfg *SMTPConfig) FromDB(bs []byte) error {
} }


type LoginSource struct { type LoginSource struct {
Id int64
ID int64 `xorm:"pk autoincr"`
Type LoginType Type LoginType
Name string `xorm:"UNIQUE"` Name string `xorm:"UNIQUE"`
IsActived bool `xorm:"NOT NULL DEFAULT false"` IsActived bool `xorm:"NOT NULL DEFAULT false"`
Updated time.Time `xorm:"UPDATED"` Updated time.Time `xorm:"UPDATED"`
} }


func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
switch colName {
case "type":
switch LoginType((*val).(int64)) {
case LDAP:
source.Cfg = new(LDAPConfig)
case SMTP:
source.Cfg = new(SMTPConfig)
case PAM:
source.Cfg = new(PAMConfig)
}
}
}

func (source *LoginSource) TypeString() string { func (source *LoginSource) TypeString() string {
return LoginTypes[source.Type] return LoginTypes[source.Type]
} }
return source.Cfg.(*PAMConfig) return source.Cfg.(*PAMConfig)
} }


func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
if colName == "type" {
ty := (*val).(int64)
switch LoginType(ty) {
case LDAP:
source.Cfg = new(LDAPConfig)
case SMTP:
source.Cfg = new(SMTPConfig)
case PAM:
source.Cfg = new(PAMConfig)
}
}
}

func CreateSource(source *LoginSource) error { func CreateSource(source *LoginSource) error {
_, err := x.Insert(source) _, err := x.Insert(source)
return err return err
} }


func GetAuths() ([]*LoginSource, error) { func GetAuths() ([]*LoginSource, error) {
var auths = make([]*LoginSource, 0, 5)
err := x.Find(&auths)
return auths, err
auths := make([]*LoginSource, 0, 5)
return auths, x.Find(&auths)
} }


func GetLoginSourceById(id int64) (*LoginSource, error) {
func GetLoginSourceByID(id int64) (*LoginSource, error) {
source := new(LoginSource) source := new(LoginSource)
has, err := x.Id(id).Get(source) has, err := x.Id(id).Get(source)
if err != nil { if err != nil {
} }


func UpdateSource(source *LoginSource) error { func UpdateSource(source *LoginSource) error {
_, err := x.Id(source.Id).AllCols().Update(source)
_, err := x.Id(source.ID).AllCols().Update(source)
return err return err
} }


func DelLoginSource(source *LoginSource) error { func DelLoginSource(source *LoginSource) error {
cnt, err := x.Count(&User{LoginSource: source.Id})
cnt, err := x.Count(&User{LoginSource: source.ID})
if err != nil { if err != nil {
return err return err
} }
if cnt > 0 { if cnt > 0 {
return ErrAuthenticationUserUsed return ErrAuthenticationUserUsed
} }
_, err = x.Id(source.Id).Delete(&LoginSource{})
_, err = x.Id(source.ID).Delete(&LoginSource{})
return err return err
} }


for _, source := range sources { for _, source := range sources {
if source.Type == LDAP { if source.Type == LDAP {
u, err := LoginUserLdapSource(nil, uname, passwd, u, err := LoginUserLdapSource(nil, uname, passwd,
source.Id, source.Cfg.(*LDAPConfig), true)
source.ID, source.Cfg.(*LDAPConfig), true)
if err == nil { if err == nil {
return u, nil return u, nil
} }
log.Warn("Fail to login(%s) by LDAP(%s): %v", uname, source.Name, err) log.Warn("Fail to login(%s) by LDAP(%s): %v", uname, source.Name, err)
} else if source.Type == SMTP { } else if source.Type == SMTP {
u, err := LoginUserSMTPSource(nil, uname, passwd, u, err := LoginUserSMTPSource(nil, uname, passwd,
source.Id, source.Cfg.(*SMTPConfig), true)
source.ID, source.Cfg.(*SMTPConfig), true)
if err == nil { if err == nil {
return u, nil return u, nil
} }
log.Warn("Fail to login(%s) by SMTP(%s): %v", uname, source.Name, err) log.Warn("Fail to login(%s) by SMTP(%s): %v", uname, source.Name, err)
} else if source.Type == PAM { } else if source.Type == PAM {
u, err := LoginUserPAMSource(nil, uname, passwd, u, err := LoginUserPAMSource(nil, uname, passwd,
source.Id, source.Cfg.(*PAMConfig), true)
source.ID, source.Cfg.(*PAMConfig), true)
if err == nil { if err == nil {
return u, nil return u, nil
} }


switch u.LoginType { switch u.LoginType {
case LDAP: case LDAP:
return LoginUserLdapSource(u, u.LoginName, passwd, source.Id, source.Cfg.(*LDAPConfig), false)
return LoginUserLdapSource(u, u.LoginName, passwd, source.ID, source.Cfg.(*LDAPConfig), false)
case SMTP: case SMTP:
return LoginUserSMTPSource(u, u.LoginName, passwd, source.Id, source.Cfg.(*SMTPConfig), false)
return LoginUserSMTPSource(u, u.LoginName, passwd, source.ID, source.Cfg.(*SMTPConfig), false)
case PAM: case PAM:
return LoginUserPAMSource(u, u.LoginName, passwd, source.Id, source.Cfg.(*PAMConfig), false)
return LoginUserPAMSource(u, u.LoginName, passwd, source.ID, source.Cfg.(*PAMConfig), false)
} }
return nil, ErrUnsupportedLoginType return nil, ErrUnsupportedLoginType
} }
return nil, nil return nil, nil
} }


var (
const (
SMTP_PLAIN = "PLAIN" SMTP_PLAIN = "PLAIN"
SMTP_LOGIN = "LOGIN" SMTP_LOGIN = "LOGIN"
SMTPAuths = []string{SMTP_PLAIN, SMTP_LOGIN}
) )


func SmtpAuth(host string, port int, a smtp.Auth, useTls bool) error {
c, err := smtp.Dial(fmt.Sprintf("%s:%d", host, port))
var (
SMTPAuths = []string{SMTP_PLAIN, SMTP_LOGIN}
)

func SMTPAuth(a smtp.Auth, cfg *SMTPConfig) error {
c, err := smtp.Dial(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port))
if err != nil { if err != nil {
return err return err
} }
return err return err
} }


if useTls {
if cfg.TLS {
if ok, _ := c.Extension("STARTTLS"); ok { if ok, _ := c.Extension("STARTTLS"); ok {
config := &tls.Config{ServerName: host}
if err = c.StartTLS(config); err != nil {
if err = c.StartTLS(&tls.Config{
InsecureSkipVerify: cfg.SkipVerify,
ServerName: cfg.Host,
}); err != nil {
return err return err
} }
} else { } else {
return nil, errors.New("Unsupported SMTP auth type") return nil, errors.New("Unsupported SMTP auth type")
} }


if err := SmtpAuth(cfg.Host, cfg.Port, auth, cfg.TLS); err != nil {
if err := SMTPAuth(auth, cfg); err != nil {
if strings.Contains(err.Error(), "Username and Password not accepted") { if strings.Contains(err.Error(), "Username and Password not accepted") {
return nil, ErrUserNotExist{u.Id, u.Name} return nil, ErrUserNotExist{u.Id, u.Name}
} }

+ 4
- 4
models/repo.go View File

Gitignores, Licenses, Readmes []string Gitignores, Licenses, Readmes []string
) )


var (
DescPattern = regexp.MustCompile(`https?://\S+`)
)

func LoadRepoConfig() { func LoadRepoConfig() {
// Load .gitignore and license files and readme templates. // Load .gitignore and license files and readme templates.
types := []string{"gitignore", "license", "readme"} types := []string{"gitignore", "license", "readme"}
return repo.OwnerID == userID return repo.OwnerID == userID
} }


var (
DescPattern = regexp.MustCompile(`https?://\S+`)
)

// DescriptionHtml does special handles to description and return HTML string. // DescriptionHtml does special handles to description and return HTML string.
func (repo *Repository) DescriptionHtml() template.HTML { func (repo *Repository) DescriptionHtml() template.HTML {
sanitize := func(s string) string { sanitize := func(s string) string {

+ 2
- 1
modules/auth/auth_form.go View File

SMTPHost string `form:"smtp_host"` SMTPHost string `form:"smtp_host"`
SMTPPort int `form:"smtp_port"` SMTPPort int `form:"smtp_port"`
TLS bool `form:"tls"` TLS bool `form:"tls"`
AllowAutoRegister bool `form:"allowautoregister"`
SkipVerify bool
AllowAutoRegister bool `form:"allowautoregister"`
PAMServiceName string PAMServiceName string
} }



+ 2
- 2
modules/bindata/bindata.go
File diff suppressed because it is too large
View File


+ 39
- 37
routers/admin/auths.go View File

case models.LDAP: case models.LDAP:
u = &models.LDAPConfig{ u = &models.LDAPConfig{
Ldapsource: ldap.Ldapsource{ Ldapsource: ldap.Ldapsource{
Name: form.Name,
Host: form.Host,
Port: form.Port,
UseSSL: form.UseSSL,
BindDN: form.BindDN,
BindPassword: form.BindPassword,
UserBase: form.UserBase,
Filter: form.Filter,
AdminFilter: form.AdminFilter,
AttributeName: form.AttributeName,
AttributeSurname: form.AttributeSurname,
AttributeMail: form.AttributeMail,
Enabled: true,
Name: form.Name,
Host: form.Host,
Port: form.Port,
UseSSL: form.UseSSL,
BindDN: form.BindDN,
BindPassword: form.BindPassword,
UserBase: form.UserBase,
Filter: form.Filter,
AdminFilter: form.AdminFilter,
AttributeName: form.AttributeName,
AttributeSurname: form.AttributeSurname,
AttributeMail: form.AttributeMail,
Enabled: true,
}, },
} }
case models.SMTP: case models.SMTP:
u = &models.SMTPConfig{ u = &models.SMTPConfig{
Auth: form.SMTPAuth,
Host: form.SMTPHost,
Port: form.SMTPPort,
TLS: form.TLS,
Auth: form.SMTPAuth,
Host: form.SMTPHost,
Port: form.SMTPPort,
TLS: form.TLS,
SkipVerify: form.SkipVerify,
} }
case models.PAM: case models.PAM:
u = &models.PAMConfig{ u = &models.PAMConfig{
ctx.Handle(404, "EditAuthSource", nil) ctx.Handle(404, "EditAuthSource", nil)
return return
} }
u, err := models.GetLoginSourceById(id)
u, err := models.GetLoginSourceByID(id)
if err != nil { if err != nil {
ctx.Handle(500, "GetLoginSourceById", err) ctx.Handle(500, "GetLoginSourceById", err)
return return
case models.LDAP: case models.LDAP:
config = &models.LDAPConfig{ config = &models.LDAPConfig{
Ldapsource: ldap.Ldapsource{ Ldapsource: ldap.Ldapsource{
Name: form.Name,
Host: form.Host,
Port: form.Port,
UseSSL: form.UseSSL,
BindDN: form.BindDN,
BindPassword: form.BindPassword,
UserBase: form.UserBase,
AttributeName: form.AttributeName,
AttributeSurname: form.AttributeSurname,
AttributeMail: form.AttributeMail,
Filter: form.Filter,
AdminFilter: form.AdminFilter,
Enabled: true,
Name: form.Name,
Host: form.Host,
Port: form.Port,
UseSSL: form.UseSSL,
BindDN: form.BindDN,
BindPassword: form.BindPassword,
UserBase: form.UserBase,
AttributeName: form.AttributeName,
AttributeSurname: form.AttributeSurname,
AttributeMail: form.AttributeMail,
Filter: form.Filter,
AdminFilter: form.AdminFilter,
Enabled: true,
}, },
} }
case models.SMTP: case models.SMTP:
config = &models.SMTPConfig{ config = &models.SMTPConfig{
Auth: form.SMTPAuth,
Host: form.SMTPHost,
Port: form.SMTPPort,
TLS: form.TLS,
Auth: form.SMTPAuth,
Host: form.SMTPHost,
Port: form.SMTPPort,
TLS: form.TLS,
SkipVerify: form.SkipVerify,
} }
case models.PAM: case models.PAM:
config = &models.PAMConfig{ config = &models.PAMConfig{
} }


u := models.LoginSource{ u := models.LoginSource{
Id: form.ID,
ID: form.ID,
Name: form.Name, Name: form.Name,
IsActived: form.IsActived, IsActived: form.IsActived,
Type: models.LoginType(form.Type), Type: models.LoginType(form.Type),
return return
} }


a, err := models.GetLoginSourceById(id)
a, err := models.GetLoginSourceByID(id)
if err != nil { if err != nil {
ctx.Handle(500, "GetLoginSourceById", err) ctx.Handle(500, "GetLoginSourceById", err)
return return

+ 6
- 2
templates/admin/auth/edit.tmpl View File

<div class="panel-header"> <div class="panel-header">
<strong>{{.i18n.Tr "admin.auths.edit"}}</strong> <strong>{{.i18n.Tr "admin.auths.edit"}}</strong>
</div> </div>
<form class="form form-align panel-body" id="auth-setting-form" action="{{AppSubUrl}}/admin/auths/{{.Source.Id}}" data-delete-url="{{AppSubUrl}}/admin/auths/{{.Source.Id}}/delete" method="post">
<form class="form form-align panel-body" id="auth-setting-form" action="{{AppSubUrl}}/admin/auths/{{.Source.ID}}" data-delete-url="{{AppSubUrl}}/admin/auths/{{.Source.ID}}/delete" method="post">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
<input type="hidden" value="{{.Source.Id}}" name="id"/>
<input type="hidden" value="{{.Source.ID}}" name="id"/>
{{$type := .Source.Type}} {{$type := .Source.Type}}
<div class="field"> <div class="field">
<label>{{.i18n.Tr "admin.auths.auth_type"}}</label> <label>{{.i18n.Tr "admin.auths.auth_type"}}</label>
<input name="tls" type="checkbox" {{if .Source.SMTP.TLS}}checked{{end}}> <input name="tls" type="checkbox" {{if .Source.SMTP.TLS}}checked{{end}}>
<strong>{{.i18n.Tr "admin.auths.enable_tls"}}</strong> <strong>{{.i18n.Tr "admin.auths.enable_tls"}}</strong>
<br> <br>
<label></label>
<input name="skip_verify" type="checkbox" {{if .Source.SMTP.SkipVerify}}checked{{end}}>
<strong>{{.i18n.Tr "admin.auths.skip_tls_verify"}}</strong>
<br>
{{end}} {{end}}
<label></label> <label></label>
<input name="allowautoregister" type="checkbox" {{if .Source.AllowAutoRegister}}checked{{end}}> <input name="allowautoregister" type="checkbox" {{if .Source.AllowAutoRegister}}checked{{end}}>

+ 3
- 3
templates/admin/auth/list.tmpl View File

<tbody> <tbody>
{{range .Sources}} {{range .Sources}}
<tr> <tr>
<td>{{.Id}}</td>
<td><a href="{{AppSubUrl}}/admin/auths/{{.Id}}">{{.Name}}</a></td>
<td>{{.ID}}</td>
<td><a href="{{AppSubUrl}}/admin/auths/{{.ID}}">{{.Name}}</a></td>
<td>{{.TypeString}}</td> <td>{{.TypeString}}</td>
<td><i class="fa fa{{if .IsActived}}-check{{end}}-square-o"></i></td> <td><i class="fa fa{{if .IsActived}}-check{{end}}-square-o"></i></td>
<td><span title="{{DateFmtLong .Updated}}">{{DateFmtShort .Updated}}</span></td> <td><span title="{{DateFmtLong .Updated}}">{{DateFmtShort .Updated}}</span></td>
<td><span title="{{DateFmtLong .Created}}">{{DateFmtShort .Created}}</span></td> <td><span title="{{DateFmtLong .Created}}">{{DateFmtShort .Created}}</span></td>
<td><a href="{{AppSubUrl}}/admin/auths/{{.Id}}"><i class="fa fa-pencil-square-o"></i></a></td>
<td><a href="{{AppSubUrl}}/admin/auths/{{.ID}}"><i class="fa fa-pencil-square-o"></i></a></td>
</tr> </tr>
{{end}} {{end}}
</tbody> </tbody>

+ 4
- 0
templates/admin/auth/new.tmpl View File

<input name="tls" type="checkbox" {{if .tls}}checked{{end}}> <input name="tls" type="checkbox" {{if .tls}}checked{{end}}>
<strong>{{.i18n.Tr "admin.auths.enable_tls"}}</strong> <strong>{{.i18n.Tr "admin.auths.enable_tls"}}</strong>
<br> <br>
<label></label>
<input name="skip_verify" type="checkbox" {{if .skip_verify}}checked{{end}}>
<strong>{{.i18n.Tr "admin.auths.skip_tls_verify"}}</strong>
<br>
</div> </div>
<label></label> <label></label>
<input name="allowautoregister" type="checkbox" {{if .allowautoregister}}checked{{end}}> <input name="allowautoregister" type="checkbox" {{if .allowautoregister}}checked{{end}}>

Loading…
Cancel
Save