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 |
} | } | ||||
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} | ||||
} | } |
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 { |
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 | ||||
} | } | ||||
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 |
<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}}> |
<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> |
<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}}> |