#1542 A way to skip TLS verify for SMTP authentication
This commit is contained in:
		
							parent
							
								
									384fbeca80
								
							
						
					
					
						commit
						ea454c21f7
					
				
					 9 changed files with 106 additions and 89 deletions
				
			
		|  | @ -794,6 +794,7 @@ auths.smtp_auth = SMTP Authorization Type | |||
| auths.smtphost = SMTP Host | ||||
| auths.smtpport = SMTP Port | ||||
| auths.enable_tls = Enable TLS Encryption | ||||
| auths.skip_tls_verify = Skip TLS Verify | ||||
| auths.pam_service_name = PAM Service Name | ||||
| auths.enable_auto_register = Enable Auto Registration | ||||
| auths.tips = Tips | ||||
|  |  | |||
|  | @ -63,10 +63,11 @@ func (cfg *LDAPConfig) ToDB() ([]byte, error) { | |||
| } | ||||
| 
 | ||||
| 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 { | ||||
|  | @ -90,7 +91,7 @@ func (cfg *PAMConfig) ToDB() ([]byte, error) { | |||
| } | ||||
| 
 | ||||
| type LoginSource struct { | ||||
| 	Id                int64 | ||||
| 	ID                int64 `xorm:"pk autoincr"` | ||||
| 	Type              LoginType | ||||
| 	Name              string          `xorm:"UNIQUE"` | ||||
| 	IsActived         bool            `xorm:"NOT NULL DEFAULT false"` | ||||
|  | @ -100,6 +101,20 @@ type LoginSource struct { | |||
| 	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 { | ||||
| 	return LoginTypes[source.Type] | ||||
| } | ||||
|  | @ -116,32 +131,17 @@ func (source *LoginSource) PAM() *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 { | ||||
| 	_, err := x.Insert(source) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| 	has, err := x.Id(id).Get(source) | ||||
| 	if err != nil { | ||||
|  | @ -153,19 +153,19 @@ func GetLoginSourceById(id int64) (*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 | ||||
| } | ||||
| 
 | ||||
| func DelLoginSource(source *LoginSource) error { | ||||
| 	cnt, err := x.Count(&User{LoginSource: source.Id}) | ||||
| 	cnt, err := x.Count(&User{LoginSource: source.ID}) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if cnt > 0 { | ||||
| 		return ErrAuthenticationUserUsed | ||||
| 	} | ||||
| 	_, err = x.Id(source.Id).Delete(&LoginSource{}) | ||||
| 	_, err = x.Id(source.ID).Delete(&LoginSource{}) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
|  | @ -206,21 +206,21 @@ func UserSignIn(uname, passwd string) (*User, error) { | |||
| 		for _, source := range sources { | ||||
| 			if source.Type == LDAP { | ||||
| 				u, err := LoginUserLdapSource(nil, uname, passwd, | ||||
| 					source.Id, source.Cfg.(*LDAPConfig), true) | ||||
| 					source.ID, source.Cfg.(*LDAPConfig), true) | ||||
| 				if err == nil { | ||||
| 					return u, nil | ||||
| 				} | ||||
| 				log.Warn("Fail to login(%s) by LDAP(%s): %v", uname, source.Name, err) | ||||
| 			} else if source.Type == SMTP { | ||||
| 				u, err := LoginUserSMTPSource(nil, uname, passwd, | ||||
| 					source.Id, source.Cfg.(*SMTPConfig), true) | ||||
| 					source.ID, source.Cfg.(*SMTPConfig), true) | ||||
| 				if err == nil { | ||||
| 					return u, nil | ||||
| 				} | ||||
| 				log.Warn("Fail to login(%s) by SMTP(%s): %v", uname, source.Name, err) | ||||
| 			} else if source.Type == PAM { | ||||
| 				u, err := LoginUserPAMSource(nil, uname, passwd, | ||||
| 					source.Id, source.Cfg.(*PAMConfig), true) | ||||
| 					source.ID, source.Cfg.(*PAMConfig), true) | ||||
| 				if err == nil { | ||||
| 					return u, nil | ||||
| 				} | ||||
|  | @ -243,11 +243,11 @@ func UserSignIn(uname, passwd string) (*User, error) { | |||
| 
 | ||||
| 	switch u.LoginType { | ||||
| 	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: | ||||
| 		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: | ||||
| 		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 | ||||
| } | ||||
|  | @ -311,14 +311,17 @@ func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) { | |||
| 	return nil, nil | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| const ( | ||||
| 	SMTP_PLAIN = "PLAIN" | ||||
| 	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 { | ||||
| 		return err | ||||
| 	} | ||||
|  | @ -328,10 +331,12 @@ func SmtpAuth(host string, port int, a smtp.Auth, useTls bool) error { | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if useTls { | ||||
| 	if cfg.TLS { | ||||
| 		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 | ||||
| 			} | ||||
| 		} else { | ||||
|  | @ -361,7 +366,7 @@ func LoginUserSMTPSource(u *User, name, passwd string, sourceId int64, cfg *SMTP | |||
| 		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") { | ||||
| 			return nil, ErrUserNotExist{u.Id, u.Name} | ||||
| 		} | ||||
|  |  | |||
|  | @ -48,10 +48,6 @@ var ( | |||
| 	Gitignores, Licenses, Readmes []string | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	DescPattern = regexp.MustCompile(`https?://\S+`) | ||||
| ) | ||||
| 
 | ||||
| func LoadRepoConfig() { | ||||
| 	// Load .gitignore and license files and readme templates.
 | ||||
| 	types := []string{"gitignore", "license", "readme"} | ||||
|  | @ -266,6 +262,10 @@ func (repo *Repository) IsOwnedBy(userID int64) bool { | |||
| 	return repo.OwnerID == userID | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	DescPattern = regexp.MustCompile(`https?://\S+`) | ||||
| ) | ||||
| 
 | ||||
| // DescriptionHtml does special handles to description and return HTML string.
 | ||||
| func (repo *Repository) DescriptionHtml() template.HTML { | ||||
| 	sanitize := func(s string) string { | ||||
|  |  | |||
|  | @ -29,7 +29,8 @@ type AuthenticationForm struct { | |||
| 	SMTPHost          string `form:"smtp_host"` | ||||
| 	SMTPPort          int    `form:"smtp_port"` | ||||
| 	TLS               bool   `form:"tls"` | ||||
| 	AllowAutoRegister bool   `form:"allowautoregister"` | ||||
| 	SkipVerify        bool | ||||
| 	AllowAutoRegister bool `form:"allowautoregister"` | ||||
| 	PAMServiceName    string | ||||
| } | ||||
| 
 | ||||
|  |  | |||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -63,27 +63,28 @@ func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) { | |||
| 	case models.LDAP: | ||||
| 		u = &models.LDAPConfig{ | ||||
| 			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: | ||||
| 		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: | ||||
| 		u = &models.PAMConfig{ | ||||
|  | @ -123,7 +124,7 @@ func EditAuthSource(ctx *middleware.Context) { | |||
| 		ctx.Handle(404, "EditAuthSource", nil) | ||||
| 		return | ||||
| 	} | ||||
| 	u, err := models.GetLoginSourceById(id) | ||||
| 	u, err := models.GetLoginSourceByID(id) | ||||
| 	if err != nil { | ||||
| 		ctx.Handle(500, "GetLoginSourceById", err) | ||||
| 		return | ||||
|  | @ -150,27 +151,28 @@ func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) { | |||
| 	case models.LDAP: | ||||
| 		config = &models.LDAPConfig{ | ||||
| 			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: | ||||
| 		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: | ||||
| 		config = &models.PAMConfig{ | ||||
|  | @ -182,7 +184,7 @@ func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) { | |||
| 	} | ||||
| 
 | ||||
| 	u := models.LoginSource{ | ||||
| 		Id:                form.ID, | ||||
| 		ID:                form.ID, | ||||
| 		Name:              form.Name, | ||||
| 		IsActived:         form.IsActived, | ||||
| 		Type:              models.LoginType(form.Type), | ||||
|  | @ -207,7 +209,7 @@ func DeleteAuthSource(ctx *middleware.Context) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	a, err := models.GetLoginSourceById(id) | ||||
| 	a, err := models.GetLoginSourceByID(id) | ||||
| 	if err != nil { | ||||
| 		ctx.Handle(500, "GetLoginSourceById", err) | ||||
| 		return | ||||
|  |  | |||
|  | @ -12,9 +12,9 @@ | |||
|                             <div class="panel-header"> | ||||
|                                 <strong>{{.i18n.Tr "admin.auths.edit"}}</strong> | ||||
|                             </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}} | ||||
|                                 <input type="hidden" value="{{.Source.Id}}" name="id"/> | ||||
|                                 <input type="hidden" value="{{.Source.ID}}" name="id"/> | ||||
|                                 {{$type := .Source.Type}} | ||||
|                                 <div class="field"> | ||||
|                                     <label>{{.i18n.Tr "admin.auths.auth_type"}}</label> | ||||
|  | @ -109,6 +109,10 @@ | |||
|                                     <input name="tls" type="checkbox" {{if .Source.SMTP.TLS}}checked{{end}}> | ||||
|                                     <strong>{{.i18n.Tr "admin.auths.enable_tls"}}</strong> | ||||
|                                     <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}} | ||||
|                                     <label></label> | ||||
|                                     <input name="allowautoregister" type="checkbox" {{if .Source.AllowAutoRegister}}checked{{end}}> | ||||
|  |  | |||
|  | @ -30,13 +30,13 @@ | |||
| 					                    <tbody> | ||||
| 					                        {{range .Sources}} | ||||
| 					                        <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><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 .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> | ||||
| 					                        {{end}} | ||||
| 					                    </tbody> | ||||
|  |  | |||
|  | @ -102,6 +102,10 @@ | |||
|                                         <input name="tls" type="checkbox" {{if .tls}}checked{{end}}> | ||||
|                                         <strong>{{.i18n.Tr "admin.auths.enable_tls"}}</strong> | ||||
|                                         <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> | ||||
|                                     <label></label> | ||||
|                                     <input name="allowautoregister" type="checkbox" {{if .allowautoregister}}checked{{end}}> | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue