| @@ -814,6 +814,7 @@ auths.port = Port | |||||
| auths.bind_dn = Bind DN | auths.bind_dn = Bind DN | ||||
| auths.bind_password = Bind Password | auths.bind_password = Bind Password | ||||
| auths.user_base = User Search Base | auths.user_base = User Search Base | ||||
| auths.user_dn = User DN | |||||
| auths.attribute_name = First name attribute | auths.attribute_name = First name attribute | ||||
| auths.attribute_surname = Surname attribute | auths.attribute_surname = Surname attribute | ||||
| auths.attribute_mail = E-mail attribute | auths.attribute_mail = E-mail attribute | ||||
| @@ -27,6 +27,7 @@ const ( | |||||
| NOTYPE LoginType = iota | NOTYPE LoginType = iota | ||||
| PLAIN | PLAIN | ||||
| LDAP | LDAP | ||||
| DLDAP | |||||
| SMTP | SMTP | ||||
| PAM | PAM | ||||
| ) | ) | ||||
| @@ -38,9 +39,10 @@ var ( | |||||
| ) | ) | ||||
| var LoginTypes = map[LoginType]string{ | var LoginTypes = map[LoginType]string{ | ||||
| LDAP: "LDAP", | |||||
| SMTP: "SMTP", | |||||
| PAM: "PAM", | |||||
| LDAP: "LDAP (via BindDN)", | |||||
| DLDAP: "LDAP (simple auth)", | |||||
| SMTP: "SMTP", | |||||
| PAM: "PAM", | |||||
| } | } | ||||
| // Ensure structs implemented interface. | // Ensure structs implemented interface. | ||||
| @@ -106,6 +108,8 @@ func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) { | |||||
| case "type": | case "type": | ||||
| switch LoginType((*val).(int64)) { | switch LoginType((*val).(int64)) { | ||||
| case LDAP: | case LDAP: | ||||
| fallthrough | |||||
| case DLDAP: | |||||
| source.Cfg = new(LDAPConfig) | source.Cfg = new(LDAPConfig) | ||||
| case SMTP: | case SMTP: | ||||
| source.Cfg = new(SMTPConfig) | source.Cfg = new(SMTPConfig) | ||||
| @@ -171,84 +175,74 @@ func DelLoginSource(source *LoginSource) error { | |||||
| // UserSignIn validates user name and password. | // UserSignIn validates user name and password. | ||||
| func UserSignIn(uname, passwd string) (*User, error) { | func UserSignIn(uname, passwd string) (*User, error) { | ||||
| u := new(User) | |||||
| var u *User | |||||
| if strings.Contains(uname, "@") { | if strings.Contains(uname, "@") { | ||||
| u = &User{Email: uname} | u = &User{Email: uname} | ||||
| } else { | } else { | ||||
| u = &User{LowerName: strings.ToLower(uname)} | u = &User{LowerName: strings.ToLower(uname)} | ||||
| } | } | ||||
| has, err := x.Get(u) | |||||
| userExists, err := x.Get(u) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| if u.LoginType == NOTYPE && has { | |||||
| u.LoginType = PLAIN | |||||
| } | |||||
| if userExists { | |||||
| switch u.LoginType { | |||||
| case NOTYPE: | |||||
| fallthrough | |||||
| case PLAIN: | |||||
| if u.ValidatePassword(passwd) { | |||||
| return u, nil | |||||
| } | |||||
| // For plain login, user must exist to reach this line. | |||||
| // Now verify password. | |||||
| if u.LoginType == PLAIN { | |||||
| if !u.ValidatePassword(passwd) { | |||||
| return nil, ErrUserNotExist{u.Id, u.Name} | return nil, ErrUserNotExist{u.Id, u.Name} | ||||
| default: | |||||
| var source LoginSource | |||||
| hasSource, err := x.Id(u.LoginSource).Get(&source) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } else if !hasSource { | |||||
| return nil, ErrLoginSourceNotExist | |||||
| } | |||||
| return ExternalUserLogin(u, u.LoginName, passwd, &source, false) | |||||
| } | } | ||||
| return u, nil | |||||
| } | } | ||||
| if !has { | |||||
| var sources []LoginSource | |||||
| if err = x.UseBool().Find(&sources, | |||||
| &LoginSource{IsActived: true, AllowAutoRegister: true}); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| var sources []LoginSource | |||||
| if err = x.UseBool().Find(&sources, &LoginSource{IsActived: true, AllowAutoRegister: true}); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| for _, source := range sources { | |||||
| if source.Type == LDAP { | |||||
| u, err := LoginUserLdapSource(nil, uname, passwd, | |||||
| 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) | |||||
| 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) | |||||
| if err == nil { | |||||
| return u, nil | |||||
| } | |||||
| log.Warn("Fail to login(%s) by PAM(%s): %v", uname, source.Name, err) | |||||
| } | |||||
| for _, source := range sources { | |||||
| u, err := ExternalUserLogin(nil, uname, passwd, &source, true) | |||||
| if err == nil { | |||||
| return u, nil | |||||
| } | } | ||||
| return nil, ErrUserNotExist{u.Id, u.Name} | |||||
| log.Warn("Failed to login '%s' via '%s': %v", uname, source.Name, err) | |||||
| } | } | ||||
| var source LoginSource | |||||
| hasSource, err := x.Id(u.LoginSource).Get(&source) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } else if !hasSource { | |||||
| return nil, ErrLoginSourceNotExist | |||||
| } else if !source.IsActived { | |||||
| return nil, ErrUserNotExist{u.Id, u.Name} | |||||
| } | |||||
| func ExternalUserLogin(u *User, name, passwd string, source *LoginSource, autoRegister bool) (*User, error) { | |||||
| if !source.IsActived { | |||||
| return nil, ErrLoginSourceNotActived | return nil, ErrLoginSourceNotActived | ||||
| } | } | ||||
| switch u.LoginType { | |||||
| switch source.Type { | |||||
| case LDAP: | case LDAP: | ||||
| return LoginUserLdapSource(u, u.LoginName, passwd, source.ID, source.Cfg.(*LDAPConfig), false) | |||||
| fallthrough | |||||
| case DLDAP: | |||||
| return LoginUserLdapSource(u, name, passwd, source, autoRegister) | |||||
| case SMTP: | case SMTP: | ||||
| return LoginUserSMTPSource(u, u.LoginName, passwd, source.ID, source.Cfg.(*SMTPConfig), false) | |||||
| return LoginUserSMTPSource(u, name, passwd, source.ID, source.Cfg.(*SMTPConfig), autoRegister) | |||||
| case PAM: | case PAM: | ||||
| return LoginUserPAMSource(u, u.LoginName, passwd, source.ID, source.Cfg.(*PAMConfig), false) | |||||
| return LoginUserPAMSource(u, name, passwd, source.ID, source.Cfg.(*PAMConfig), autoRegister) | |||||
| } | } | ||||
| return nil, ErrUnsupportedLoginType | return nil, ErrUnsupportedLoginType | ||||
| } | } | ||||
| @@ -256,8 +250,10 @@ func UserSignIn(uname, passwd string) (*User, error) { | |||||
| // Create a local user if success | // Create a local user if success | ||||
| // Return the same LoginUserPlain semantic | // Return the same LoginUserPlain semantic | ||||
| // FIXME: https://github.com/gogits/gogs/issues/672 | // FIXME: https://github.com/gogits/gogs/issues/672 | ||||
| func LoginUserLdapSource(u *User, name, passwd string, sourceId int64, cfg *LDAPConfig, autoRegister bool) (*User, error) { | |||||
| fn, sn, mail, admin, logged := cfg.Ldapsource.SearchEntry(name, passwd) | |||||
| func LoginUserLdapSource(u *User, name, passwd string, source *LoginSource, autoRegister bool) (*User, error) { | |||||
| cfg := source.Cfg.(*LDAPConfig) | |||||
| directBind := (source.Type == DLDAP) | |||||
| fn, sn, mail, admin, logged := cfg.Ldapsource.SearchEntry(name, passwd, directBind) | |||||
| if !logged { | if !logged { | ||||
| // User not in LDAP, do nothing | // User not in LDAP, do nothing | ||||
| return nil, ErrUserNotExist{0, name} | return nil, ErrUserNotExist{0, name} | ||||
| @@ -276,8 +272,8 @@ func LoginUserLdapSource(u *User, name, passwd string, sourceId int64, cfg *LDAP | |||||
| LowerName: strings.ToLower(name), | LowerName: strings.ToLower(name), | ||||
| Name: name, | Name: name, | ||||
| FullName: fn + " " + sn, | FullName: fn + " " + sn, | ||||
| LoginType: LDAP, | |||||
| LoginSource: sourceId, | |||||
| LoginType: source.Type, | |||||
| LoginSource: source.ID, | |||||
| LoginName: name, | LoginName: name, | ||||
| Passwd: passwd, | Passwd: passwd, | ||||
| Email: mail, | Email: mail, | ||||
| @@ -19,6 +19,7 @@ type AuthenticationForm struct { | |||||
| BindDN string `form:"bind_dn"` | BindDN string `form:"bind_dn"` | ||||
| BindPassword string | BindPassword string | ||||
| UserBase string | UserBase string | ||||
| UserDN string `form:"user_dn"` | |||||
| AttributeName string | AttributeName string | ||||
| AttributeSurname string | AttributeSurname string | ||||
| AttributeMail string | AttributeMail string | ||||
| @@ -22,6 +22,7 @@ type Ldapsource struct { | |||||
| BindDN string // DN to bind with | BindDN string // DN to bind with | ||||
| BindPassword string // Bind DN password | BindPassword string // Bind DN password | ||||
| UserBase string // Base search path for users | UserBase string // Base search path for users | ||||
| UserDN string // Template for the DN of the user for simple auth | |||||
| AttributeName string // First name attribute | AttributeName string // First name attribute | ||||
| AttributeSurname string // Surname attribute | AttributeSurname string // Surname attribute | ||||
| AttributeMail string // E-mail attribute | AttributeMail string // E-mail attribute | ||||
| @@ -78,10 +79,19 @@ func (ls Ldapsource) FindUserDN(name string) (string, bool) { | |||||
| } | } | ||||
| // searchEntry : search an LDAP source if an entry (name, passwd) is valid and in the specific filter | // searchEntry : search an LDAP source if an entry (name, passwd) is valid and in the specific filter | ||||
| func (ls Ldapsource) SearchEntry(name, passwd string) (string, string, string, bool, bool) { | |||||
| userDN, found := ls.FindUserDN(name) | |||||
| if !found { | |||||
| return "", "", "", false, false | |||||
| func (ls Ldapsource) SearchEntry(name, passwd string, directBind bool) (string, string, string, bool, bool) { | |||||
| var userDN string | |||||
| if directBind { | |||||
| log.Trace("LDAP will bind directly via UserDN template: %s", ls.UserDN) | |||||
| userDN = fmt.Sprintf(ls.UserDN, name) | |||||
| } else { | |||||
| log.Trace("LDAP will use BindDN.") | |||||
| var found bool | |||||
| userDN, found = ls.FindUserDN(name) | |||||
| if !found { | |||||
| return "", "", "", false, false | |||||
| } | |||||
| } | } | ||||
| l, err := ldapDial(ls) | l, err := ldapDial(ls) | ||||
| @@ -112,7 +122,12 @@ func (ls Ldapsource) SearchEntry(name, passwd string) (string, string, string, b | |||||
| log.Error(4, "LDAP Search failed unexpectedly! (%v)", err) | log.Error(4, "LDAP Search failed unexpectedly! (%v)", err) | ||||
| return "", "", "", false, false | return "", "", "", false, false | ||||
| } else if len(sr.Entries) < 1 { | } else if len(sr.Entries) < 1 { | ||||
| log.Error(4, "LDAP Search failed unexpectedly! (0 entries)") | |||||
| if directBind { | |||||
| log.Error(4, "User filter inhibited user login.") | |||||
| } else { | |||||
| log.Error(4, "LDAP Search failed unexpectedly! (0 entries)") | |||||
| } | |||||
| return "", "", "", false, false | return "", "", "", false, false | ||||
| } | } | ||||
| @@ -57,10 +57,10 @@ var Gogs = {}; | |||||
| }); | }); | ||||
| $.fn.extend({ | $.fn.extend({ | ||||
| toggleHide: function () { | toggleHide: function () { | ||||
| $(this).addClass("hidden"); | |||||
| $(this).each(function(n, v) { $(v).addClass("hidden"); }); | |||||
| }, | }, | ||||
| toggleShow: function () { | toggleShow: function () { | ||||
| $(this).removeClass("hidden"); | |||||
| $(this).each(function(n, v) { $(v).removeClass("hidden"); }); | |||||
| }, | }, | ||||
| toggleAjax: function (successCallback, errorCallback) { | toggleAjax: function (successCallback, errorCallback) { | ||||
| var url = $(this).data("ajax"); | var url = $(this).data("ajax"); | ||||
| @@ -775,24 +775,20 @@ function initAdmin() { | |||||
| $form.attr('action', $form.data('delete-url')); | $form.attr('action', $form.data('delete-url')); | ||||
| }); | }); | ||||
| // Create authorization. | |||||
| // Create authorization. Keep list in sync with models/login.go. | |||||
| var all_auths = ['none', 'plain', 'ldap', 'dldap', 'smtp', 'pam']; | |||||
| $('#auth-type').on("change", function () { | $('#auth-type').on("change", function () { | ||||
| var v = $(this).val(); | var v = $(this).val(); | ||||
| if (v == 2) { | |||||
| $('.ldap').toggleShow(); | |||||
| $('.smtp').toggleHide(); | |||||
| $('.pam').toggleHide(); | |||||
| } | |||||
| if (v == 3) { | |||||
| $('.smtp').toggleShow(); | |||||
| $('.ldap').toggleHide(); | |||||
| $('.pam').toggleHide(); | |||||
| } | |||||
| if (v == 4) { | |||||
| $('.pam').toggleShow(); | |||||
| $('.smtp').toggleHide(); | |||||
| $('.ldap').toggleHide(); | |||||
| } | |||||
| if (v >= all_auths.length) return; | |||||
| // Hide all through their class names. | |||||
| $.each(all_auths, function(i, type) { | |||||
| $('.' + type).toggleHide(); | |||||
| }); | |||||
| // Show the selected one. | |||||
| var selected = all_auths[v]; | |||||
| $('.' + selected).toggleShow(); | |||||
| }); | }); | ||||
| // Delete authorization. | // Delete authorization. | ||||
| @@ -61,6 +61,8 @@ func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) { | |||||
| var u core.Conversion | var u core.Conversion | ||||
| switch models.LoginType(form.Type) { | switch models.LoginType(form.Type) { | ||||
| case models.LDAP: | case models.LDAP: | ||||
| fallthrough | |||||
| case models.DLDAP: | |||||
| u = &models.LDAPConfig{ | u = &models.LDAPConfig{ | ||||
| Ldapsource: ldap.Ldapsource{ | Ldapsource: ldap.Ldapsource{ | ||||
| Name: form.Name, | Name: form.Name, | ||||
| @@ -68,13 +70,14 @@ func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) { | |||||
| Port: form.Port, | Port: form.Port, | ||||
| UseSSL: form.UseSSL, | UseSSL: form.UseSSL, | ||||
| BindDN: form.BindDN, | BindDN: form.BindDN, | ||||
| UserDN: form.UserDN, | |||||
| BindPassword: form.BindPassword, | BindPassword: form.BindPassword, | ||||
| UserBase: form.UserBase, | UserBase: form.UserBase, | ||||
| Filter: form.Filter, | |||||
| AdminFilter: form.AdminFilter, | |||||
| AttributeName: form.AttributeName, | AttributeName: form.AttributeName, | ||||
| AttributeSurname: form.AttributeSurname, | AttributeSurname: form.AttributeSurname, | ||||
| AttributeMail: form.AttributeMail, | AttributeMail: form.AttributeMail, | ||||
| Filter: form.Filter, | |||||
| AdminFilter: form.AdminFilter, | |||||
| Enabled: true, | Enabled: true, | ||||
| }, | }, | ||||
| } | } | ||||
| @@ -149,6 +152,8 @@ func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) { | |||||
| var config core.Conversion | var config core.Conversion | ||||
| switch models.LoginType(form.Type) { | switch models.LoginType(form.Type) { | ||||
| case models.LDAP: | case models.LDAP: | ||||
| fallthrough | |||||
| case models.DLDAP: | |||||
| config = &models.LDAPConfig{ | config = &models.LDAPConfig{ | ||||
| Ldapsource: ldap.Ldapsource{ | Ldapsource: ldap.Ldapsource{ | ||||
| Name: form.Name, | Name: form.Name, | ||||
| @@ -156,6 +161,7 @@ func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) { | |||||
| Port: form.Port, | Port: form.Port, | ||||
| UseSSL: form.UseSSL, | UseSSL: form.UseSSL, | ||||
| BindDN: form.BindDN, | BindDN: form.BindDN, | ||||
| UserDN: form.UserDN, | |||||
| BindPassword: form.BindPassword, | BindPassword: form.BindPassword, | ||||
| UserBase: form.UserBase, | UserBase: form.UserBase, | ||||
| AttributeName: form.AttributeName, | AttributeName: form.AttributeName, | ||||
| @@ -30,7 +30,7 @@ | |||||
| <input class="ipt ipt-large ipt-radius {{if .Err_AuthName}}ipt-error{{end}}" id="name" name="name" value="{{.Source.Name}}" required /> | <input class="ipt ipt-large ipt-radius {{if .Err_AuthName}}ipt-error{{end}}" id="name" name="name" value="{{.Source.Name}}" required /> | ||||
| </div> | </div> | ||||
| {{if eq $type 2}} | |||||
| {{if eq $type 2 3}} | |||||
| <div class="field"> | <div class="field"> | ||||
| <label class="req" for="host">{{.i18n.Tr "admin.auths.host"}}</label> | <label class="req" for="host">{{.i18n.Tr "admin.auths.host"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_Host}}ipt-error{{end}}" id="host" name="host" value="{{.Source.LDAP.Host}}" required /> | <input class="ipt ipt-large ipt-radius {{if .Err_Host}}ipt-error{{end}}" id="host" name="host" value="{{.Source.LDAP.Host}}" required /> | ||||
| @@ -43,6 +43,7 @@ | |||||
| <label for="use_ssl">{{.i18n.Tr "admin.auths.enable_tls"}}</label> | <label for="use_ssl">{{.i18n.Tr "admin.auths.enable_tls"}}</label> | ||||
| <input name="use_ssl" type="checkbox" {{if .Source.LDAP.UseSSL}}checked{{end}}> | <input name="use_ssl" type="checkbox" {{if .Source.LDAP.UseSSL}}checked{{end}}> | ||||
| </div> | </div> | ||||
| {{if eq $type 2}} | |||||
| <div class="field"> | <div class="field"> | ||||
| <label for="bind_dn">{{.i18n.Tr "admin.auths.bind_dn"}}</label> | <label for="bind_dn">{{.i18n.Tr "admin.auths.bind_dn"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_BindDN}}ipt-error{{end}}" id="bind_dn" name="bind_dn" value="{{.Source.LDAP.BindDN}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_BindDN}}ipt-error{{end}}" id="bind_dn" name="bind_dn" value="{{.Source.LDAP.BindDN}}" /> | ||||
| @@ -55,6 +56,13 @@ | |||||
| <label class="req" for="user_base">{{.i18n.Tr "admin.auths.user_base"}}</label> | <label class="req" for="user_base">{{.i18n.Tr "admin.auths.user_base"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_UserBase}}ipt-error{{end}}" id="user_base" name="user_base" value="{{.Source.LDAP.UserBase}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_UserBase}}ipt-error{{end}}" id="user_base" name="user_base" value="{{.Source.LDAP.UserBase}}" /> | ||||
| </div> | </div> | ||||
| {{end}} | |||||
| {{if eq $type 3}} | |||||
| <div class="field"> | |||||
| <label class="req" for="user_dn">{{.i18n.Tr "admin.auths.user_dn"}}</label> | |||||
| <input class="ipt ipt-large ipt-radius {{if .Err_UserDN}}ipt-error{{end}}" id="user_dn" name="user_dn" value="{{.Source.LDAP.UserDN}}" /> | |||||
| </div> | |||||
| {{end}} | |||||
| <div class="field"> | <div class="field"> | ||||
| <label class="req" for="filter">{{.i18n.Tr "admin.auths.filter"}}</label> | <label class="req" for="filter">{{.i18n.Tr "admin.auths.filter"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_Filter}}ipt-error{{end}}" id="filter" name="filter" value="{{.Source.LDAP.Filter}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_Filter}}ipt-error{{end}}" id="filter" name="filter" value="{{.Source.LDAP.Filter}}" /> | ||||
| @@ -76,7 +84,8 @@ | |||||
| <input class="ipt ipt-large ipt-radius {{if .Err_Attributes}}ipt-error{{end}}" id="attribute_mail" name="attribute_mail" value="{{.Source.LDAP.AttributeMail}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_Attributes}}ipt-error{{end}}" id="attribute_mail" name="attribute_mail" value="{{.Source.LDAP.AttributeMail}}" /> | ||||
| </div> | </div> | ||||
| {{else if eq $type 3}} | |||||
| {{else if eq $type 4}} | |||||
| <div class="field"> | <div class="field"> | ||||
| <label class="req">{{.i18n.Tr "admin.auths.smtp_auth"}}</label> | <label class="req">{{.i18n.Tr "admin.auths.smtp_auth"}}</label> | ||||
| <select name="smtp_auth"> | <select name="smtp_auth"> | ||||
| @@ -96,7 +105,7 @@ | |||||
| <input class="ipt ipt-large ipt-radius {{if .Err_SmtpPort}}ipt-error{{end}}" id="smtp_port" name="smtp_port" value="{{.Source.SMTP.Port}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_SmtpPort}}ipt-error{{end}}" id="smtp_port" name="smtp_port" value="{{.Source.SMTP.Port}}" /> | ||||
| </div> | </div> | ||||
| {{else if eq $type 4}} | |||||
| {{else if eq $type 5}} | |||||
| <div class="field"> | <div class="field"> | ||||
| <label class="req" for="pam_service_name">{{.i18n.Tr "admin.auths.pam_service_name"}}</label> | <label class="req" for="pam_service_name">{{.i18n.Tr "admin.auths.pam_service_name"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_PAMServiceName}}ipt-error{{end}}" id="pam_service_name" name="pam_service_name" value="{{.Source.PAM.ServiceName}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_PAMServiceName}}ipt-error{{end}}" id="pam_service_name" name="pam_service_name" value="{{.Source.PAM.ServiceName}}" /> | ||||
| @@ -104,7 +113,7 @@ | |||||
| {{end}} | {{end}} | ||||
| <div class="field"> | <div class="field"> | ||||
| {{if eq $type 3}} | |||||
| {{if eq $type 4}} | |||||
| <label></label> | <label></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> | ||||
| @@ -26,48 +26,52 @@ | |||||
| <label class="req" for="name">{{.i18n.Tr "admin.auths.auth_name"}}</label> | <label class="req" for="name">{{.i18n.Tr "admin.auths.auth_name"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_AuthName}}ipt-error{{end}}" id="name" name="name" value="{{.name}}" required /> | <input class="ipt ipt-large ipt-radius {{if .Err_AuthName}}ipt-error{{end}}" id="name" name="name" value="{{.name}}" required /> | ||||
| </div> | </div> | ||||
| <div class="ldap"> | |||||
| <div class="field"> | |||||
| <div class="dldap ldap"> | |||||
| <div class="dldap ldap field"> | |||||
| <label class="req" for="host">{{.i18n.Tr "admin.auths.host"}}</label> | <label class="req" for="host">{{.i18n.Tr "admin.auths.host"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_Host}}ipt-error{{end}}" id="host" name="host" value="{{.host}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_Host}}ipt-error{{end}}" id="host" name="host" value="{{.host}}" /> | ||||
| </div> | </div> | ||||
| <div class="field"> | |||||
| <div class="dldap ldap field"> | |||||
| <label class="req" for="port">{{.i18n.Tr "admin.auths.port"}}</label> | <label class="req" for="port">{{.i18n.Tr "admin.auths.port"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_Port}}ipt-error{{end}}" id="port" name="port" value="{{.port}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_Port}}ipt-error{{end}}" id="port" name="port" value="{{.port}}" /> | ||||
| </div> | </div> | ||||
| <div class="field"> | |||||
| <div class="dldap ldap field"> | |||||
| <label for="use_ssl">{{.i18n.Tr "admin.auths.enable_tls"}}</label> | <label for="use_ssl">{{.i18n.Tr "admin.auths.enable_tls"}}</label> | ||||
| <input name="use_ssl" type="checkbox" {{if .use_ssl}}checked{{end}}> | <input name="use_ssl" type="checkbox" {{if .use_ssl}}checked{{end}}> | ||||
| </div> | </div> | ||||
| <div class="field"> | |||||
| <div class="ldap field"> | |||||
| <label class="req" for="bind_dn">{{.i18n.Tr "admin.auths.bind_dn"}}</label> | <label class="req" for="bind_dn">{{.i18n.Tr "admin.auths.bind_dn"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_BindDN}}ipt-error{{end}}" id="bind_dn" name="bind_dn" value="{{.bind_dn}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_BindDN}}ipt-error{{end}}" id="bind_dn" name="bind_dn" value="{{.bind_dn}}" /> | ||||
| </div> | </div> | ||||
| <div class="field"> | |||||
| <div class="ldap field"> | |||||
| <label class="req" for="bind_password">{{.i18n.Tr "admin.auths.bind_password"}}</label> | <label class="req" for="bind_password">{{.i18n.Tr "admin.auths.bind_password"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_BindPassword}}ipt-error{{end}}" id="bind_password" name="bind_password" type="password" value="{{.bind_password}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_BindPassword}}ipt-error{{end}}" id="bind_password" name="bind_password" type="password" value="{{.bind_password}}" /> | ||||
| </div> | </div> | ||||
| <div class="field"> | |||||
| <div class="ldap field"> | |||||
| <label class="req" for="user_base">{{.i18n.Tr "admin.auths.user_base"}}</label> | <label class="req" for="user_base">{{.i18n.Tr "admin.auths.user_base"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_UserBase}}ipt-error{{end}}" id="user_base" name="user_base" value="{{.user_base}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_UserBase}}ipt-error{{end}}" id="user_base" name="user_base" value="{{.user_base}}" /> | ||||
| </div> | </div> | ||||
| <div class="field"> | |||||
| <div class="dldap field hidden"> | |||||
| <label class="req" for="user_dn">{{.i18n.Tr "admin.auths.user_dn"}}</label> | |||||
| <input class="ipt ipt-large ipt-radius {{if .Err_UserDN}}ipt-error{{end}}" id="user_dn" name="user_dn" value="{{.user_dn}}" /> | |||||
| </div> | |||||
| <div class="dldap ldap field"> | |||||
| <label class="req" for="filter">{{.i18n.Tr "admin.auths.filter"}}</label> | <label class="req" for="filter">{{.i18n.Tr "admin.auths.filter"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_Filter}}ipt-error{{end}}" id="filter" name="filter" value="{{.filter}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_Filter}}ipt-error{{end}}" id="filter" name="filter" value="{{.filter}}" /> | ||||
| </div> | </div> | ||||
| <div class="field"> | |||||
| <div class="dldap ldap field"> | |||||
| <label for="filter">{{.i18n.Tr "admin.auths.admin_filter"}}</label> | <label for="filter">{{.i18n.Tr "admin.auths.admin_filter"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_AdminFilter}}ipt-error{{end}}" id="admin_filter" name="admin_filter" value="{{.admin_filter}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_AdminFilter}}ipt-error{{end}}" id="admin_filter" name="admin_filter" value="{{.admin_filter}}" /> | ||||
| </div> | </div> | ||||
| <div class="field"> | |||||
| <div class="dldap ldap field"> | |||||
| <label for="attribute_name">{{.i18n.Tr "admin.auths.attribute_name"}}</label> | <label for="attribute_name">{{.i18n.Tr "admin.auths.attribute_name"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_AttributeName}}ipt-error{{end}}" id="attribute_name" name="attribute_name" value="{{.attribute_name}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_AttributeName}}ipt-error{{end}}" id="attribute_name" name="attribute_name" value="{{.attribute_name}}" /> | ||||
| </div> | </div> | ||||
| <div class="field"> | |||||
| <div class="dldap ldap field"> | |||||
| <label for="attribute_surname">{{.i18n.Tr "admin.auths.attribute_surname"}}</label> | <label for="attribute_surname">{{.i18n.Tr "admin.auths.attribute_surname"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_AttributeSurname}}ipt-error{{end}}" id="attribute_surname" name="attribute_surname" value="{{.attribute_surname}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_AttributeSurname}}ipt-error{{end}}" id="attribute_surname" name="attribute_surname" value="{{.attribute_surname}}" /> | ||||
| </div> | </div> | ||||
| <div class="field"> | |||||
| <div class="dldap ldap field"> | |||||
| <label class="req" for="attribute_mail">{{.i18n.Tr "admin.auths.attribute_mail"}}</label> | <label class="req" for="attribute_mail">{{.i18n.Tr "admin.auths.attribute_mail"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_AttributeMail}}ipt-error{{end}}" id="attribute_mail" name="attribute_mail" value="{{.attribute_mail}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_AttributeMail}}ipt-error{{end}}" id="attribute_mail" name="attribute_mail" value="{{.attribute_mail}}" /> | ||||
| </div> | </div> | ||||