Browse Source

Use SecurityProtocol to replace UseSSL in LDAP config

Initially proposed by #2376 and fixes #3068 as well.
Unknwon 4 years ago
parent
commit
401bf944ef

+ 1 - 1
README.md

@@ -3,7 +3,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
3 3
 
4 4
 ![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true)
5 5
 
6
-##### Current tip version: 0.9.36 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
6
+##### Current tip version: 0.9.37 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
7 7
 
8 8
 | Web | UI  | Preview  |
9 9
 |:-------------:|:-------:|:-------:|

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

@@ -919,6 +919,7 @@ auths.enabled = Enabled
919 919
 auths.updated = Updated
920 920
 auths.auth_type = Authentication Type
921 921
 auths.auth_name = Authentication Name
922
+auths.security_protocol = Security Protocol
922 923
 auths.domain = Domain
923 924
 auths.host = Host
924 925
 auths.port = Port

+ 1 - 1
glide.lock

@@ -6,7 +6,7 @@ imports:
6 6
   subpackages:
7 7
   - memcache
8 8
 - name: github.com/codegangsta/cli
9
-  version: e5bef42c62aa7d25aba4880dc02b7624f01e9e19
9
+  version: 1efa31f08b9333f1bd4882d61f9d668a70cd902e
10 10
 - name: github.com/go-macaron/binding
11 11
   version: bd00823a7e9aa00cb3b1738fde244573ba7cce2c
12 12
 - name: github.com/go-macaron/cache

+ 1 - 1
gogs.go

@@ -17,7 +17,7 @@ import (
17 17
 	"github.com/gogits/gogs/modules/setting"
18 18
 )
19 19
 
20
-const APP_VER = "0.9.36.0704"
20
+const APP_VER = "0.9.37.0708"
21 21
 
22 22
 func init() {
23 23
 	runtime.GOMAXPROCS(runtime.NumCPU())

+ 22 - 6
models/login.go

@@ -23,6 +23,11 @@ import (
23 23
 	"github.com/gogits/gogs/modules/log"
24 24
 )
25 25
 
26
+var (
27
+	ErrAuthenticationAlreadyExist = errors.New("Authentication already exist")
28
+	ErrAuthenticationUserUsed     = errors.New("Authentication has been used by some users")
29
+)
30
+
26 31
 type LoginType int
27 32
 
28 33
 // Note: new type must be added at the end of list to maintain compatibility.
@@ -35,11 +40,6 @@ const (
35 40
 	LOGIN_DLDAP            // 5
36 41
 )
37 42
 
38
-var (
39
-	ErrAuthenticationAlreadyExist = errors.New("Authentication already exist")
40
-	ErrAuthenticationUserUsed     = errors.New("Authentication has been used by some users")
41
-)
42
-
43 43
 var LoginNames = map[LoginType]string{
44 44
 	LOGIN_LDAP:  "LDAP (via BindDN)",
45 45
 	LOGIN_DLDAP: "LDAP (simple auth)", // Via direct bind
@@ -47,6 +47,12 @@ var LoginNames = map[LoginType]string{
47 47
 	LOGIN_PAM:   "PAM",
48 48
 }
49 49
 
50
+var SecurityProtocolNames = map[ldap.SecurityProtocol]string{
51
+	ldap.SECURITY_PROTOCOL_UNENCRYPTED: "Unencrypted",
52
+	ldap.SECURITY_PROTOCOL_LDAPS:       "LDAPS",
53
+	ldap.SECURITY_PROTOCOL_START_TLS:   "StartTLS",
54
+}
55
+
50 56
 // Ensure structs implemented interface.
51 57
 var (
52 58
 	_ core.Conversion = &LDAPConfig{}
@@ -66,6 +72,10 @@ func (cfg *LDAPConfig) ToDB() ([]byte, error) {
66 72
 	return json.Marshal(cfg)
67 73
 }
68 74
 
75
+func (cfg *LDAPConfig) SecurityProtocolName() string {
76
+	return SecurityProtocolNames[cfg.SecurityProtocol]
77
+}
78
+
69 79
 type SMTPConfig struct {
70 80
 	Auth           string
71 81
 	Host           string
@@ -173,10 +183,16 @@ func (source *LoginSource) IsPAM() bool {
173 183
 	return source.Type == LOGIN_PAM
174 184
 }
175 185
 
186
+func (source *LoginSource) HasTLS() bool {
187
+	return ((source.IsLDAP() || source.IsDLDAP()) &&
188
+		source.LDAP().SecurityProtocol > ldap.SECURITY_PROTOCOL_UNENCRYPTED) ||
189
+		source.IsSMTP()
190
+}
191
+
176 192
 func (source *LoginSource) UseTLS() bool {
177 193
 	switch source.Type {
178 194
 	case LOGIN_LDAP, LOGIN_DLDAP:
179
-		return source.LDAP().UseSSL
195
+		return source.LDAP().SecurityProtocol != ldap.SECURITY_PROTOCOL_UNENCRYPTED
180 196
 	case LOGIN_SMTP:
181 197
 		return source.SMTP().TLS
182 198
 	}

+ 10 - 8
models/migrations/migrations.go

@@ -59,14 +59,15 @@ type Version struct {
59 59
 // If you want to "retire" a migration, remove it from the top of the list and
60 60
 // update _MIN_VER_DB accordingly
61 61
 var migrations = []Migration{
62
-	NewMigration("fix locale file load panic", fixLocaleFileLoadPanic),                 // V4 -> V5:v0.6.0
63
-	NewMigration("trim action compare URL prefix", trimCommitActionAppUrlPrefix),       // V5 -> V6:v0.6.3
64
-	NewMigration("generate issue-label from issue", issueToIssueLabel),                 // V6 -> V7:v0.6.4
65
-	NewMigration("refactor attachment table", attachmentRefactor),                      // V7 -> V8:v0.6.4
66
-	NewMigration("rename pull request fields", renamePullRequestFields),                // V8 -> V9:v0.6.16
67
-	NewMigration("clean up migrate repo info", cleanUpMigrateRepoInfo),                 // V9 -> V10:v0.6.20
68
-	NewMigration("generate rands and salt for organizations", generateOrgRandsAndSalt), // V10 -> V11:v0.8.5
69
-	NewMigration("convert date to unix timestamp", convertDateToUnix),                  // V11 -> V12:v0.9.2
62
+	NewMigration("fix locale file load panic", fixLocaleFileLoadPanic),                           // V4 -> V5:v0.6.0
63
+	NewMigration("trim action compare URL prefix", trimCommitActionAppUrlPrefix),                 // V5 -> V6:v0.6.3
64
+	NewMigration("generate issue-label from issue", issueToIssueLabel),                           // V6 -> V7:v0.6.4
65
+	NewMigration("refactor attachment table", attachmentRefactor),                                // V7 -> V8:v0.6.4
66
+	NewMigration("rename pull request fields", renamePullRequestFields),                          // V8 -> V9:v0.6.16
67
+	NewMigration("clean up migrate repo info", cleanUpMigrateRepoInfo),                           // V9 -> V10:v0.6.20
68
+	NewMigration("generate rands and salt for organizations", generateOrgRandsAndSalt),           // V10 -> V11:v0.8.5
69
+	NewMigration("convert date to unix timestamp", convertDateToUnix),                            // V11 -> V12:v0.9.2
70
+	NewMigration("convert LDAP UseSSL option to SecurityProtocol", ldapUseSSLToSecurityProtocol), // V12 -> V13:v0.9.37
70 71
 }
71 72
 
72 73
 // Migrate database to current version
@@ -580,6 +581,7 @@ type TWebhook struct {
580 581
 func (t *TWebhook) TableName() string { return "webhook" }
581 582
 
582 583
 func convertDateToUnix(x *xorm.Engine) (err error) {
584
+	log.Info("This migration could take up to minutes, please be patient.")
583 585
 	type Bean struct {
584 586
 		ID         int64 `xorm:"pk autoincr"`
585 587
 		Created    time.Time

+ 52 - 0
models/migrations/v13.go

@@ -0,0 +1,52 @@
1
+// Copyright 2016 The Gogs Authors. All rights reserved.
2
+// Use of this source code is governed by a MIT-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package migrations
6
+
7
+import (
8
+	"encoding/json"
9
+	"fmt"
10
+	"strings"
11
+
12
+	"github.com/Unknwon/com"
13
+	"github.com/go-xorm/xorm"
14
+)
15
+
16
+func ldapUseSSLToSecurityProtocol(x *xorm.Engine) error {
17
+	results, err := x.Query("SELECT `id`,`cfg` FROM `login_source` WHERE `type` = 2 OR `type` = 5")
18
+	if err != nil {
19
+		if strings.Contains(err.Error(), "no such column") {
20
+			return nil
21
+		}
22
+		return fmt.Errorf("select LDAP login sources: %v", err)
23
+	}
24
+
25
+	sess := x.NewSession()
26
+	defer sessionRelease(sess)
27
+	if err = sess.Begin(); err != nil {
28
+		return err
29
+	}
30
+
31
+	for _, result := range results {
32
+		cfg := map[string]interface{}{}
33
+		if err = json.Unmarshal(result["cfg"], &cfg); err != nil {
34
+			return fmt.Errorf("decode JSON config: %v", err)
35
+		}
36
+		if com.ToStr(cfg["UseSSL"]) == "true" {
37
+			cfg["SecurityProtocol"] = 1 // LDAPS
38
+		}
39
+		delete(cfg, "UseSSL")
40
+
41
+		data, err := json.Marshal(&cfg)
42
+		if err != nil {
43
+			return fmt.Errorf("encode JSON config: %v", err)
44
+		}
45
+
46
+		if _, err = sess.Exec("UPDATE `login_source` SET `cfg`=? WHERE `id`=?",
47
+			string(data), com.StrTo(result["id"]).MustInt64()); err != nil {
48
+			return fmt.Errorf("update config column: %v", err)
49
+		}
50
+	}
51
+	return sess.Commit()
52
+}

+ 1 - 0
modules/auth/auth_form.go

@@ -31,6 +31,7 @@ type AuthenticationForm struct {
31 31
 	SMTPHost          string
32 32
 	SMTPPort          int
33 33
 	AllowedDomains    string
34
+	SecurityProtocol  int `binding:"Range(0,2)"`
34 35
 	TLS               bool
35 36
 	SkipVerify        bool
36 37
 	PAMServiceName    string

+ 48 - 25
modules/auth/ldap/ldap.go

@@ -16,12 +16,21 @@ import (
16 16
 	"github.com/gogits/gogs/modules/log"
17 17
 )
18 18
 
19
+type SecurityProtocol int
20
+
21
+// Note: new type must be added at the end of list to maintain compatibility.
22
+const (
23
+	SECURITY_PROTOCOL_UNENCRYPTED SecurityProtocol = iota
24
+	SECURITY_PROTOCOL_LDAPS
25
+	SECURITY_PROTOCOL_START_TLS
26
+)
27
+
19 28
 // Basic LDAP authentication service
20 29
 type Source struct {
21 30
 	Name              string // canonical name (ie. corporate.ad)
22 31
 	Host              string // LDAP host
23 32
 	Port              int    // port number
24
-	UseSSL            bool   // Use SSL
33
+	SecurityProtocol  SecurityProtocol
25 34
 	SkipVerify        bool
26 35
 	BindDN            string // DN to bind with
27 36
 	BindPassword      string // Bind DN password
@@ -102,9 +111,46 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
102 111
 	return userDN, true
103 112
 }
104 113
 
114
+func dial(ls *Source) (*ldap.Conn, error) {
115
+	log.Trace("Dialing LDAP with security protocol (%v) without verifying: %v", ls.SecurityProtocol, ls.SkipVerify)
116
+
117
+	tlsCfg := &tls.Config{
118
+		ServerName:         ls.Host,
119
+		InsecureSkipVerify: ls.SkipVerify,
120
+	}
121
+	if ls.SecurityProtocol == SECURITY_PROTOCOL_LDAPS {
122
+		return ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port), tlsCfg)
123
+	}
124
+
125
+	conn, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port))
126
+	if err != nil {
127
+		return nil, fmt.Errorf("Dial: %v", err)
128
+	}
129
+
130
+	if ls.SecurityProtocol == SECURITY_PROTOCOL_START_TLS {
131
+		if err = conn.StartTLS(tlsCfg); err != nil {
132
+			conn.Close()
133
+			return nil, fmt.Errorf("StartTLS: %v", err)
134
+		}
135
+	}
136
+
137
+	return conn, nil
138
+}
139
+
140
+func bindUser(l *ldap.Conn, userDN, passwd string) error {
141
+	log.Trace("Binding with userDN: %s", userDN)
142
+	err := l.Bind(userDN, passwd)
143
+	if err != nil {
144
+		log.Debug("LDAP auth. failed for %s, reason: %v", userDN, err)
145
+		return err
146
+	}
147
+	log.Trace("Bound successfully with userDN: %s", userDN)
148
+	return err
149
+}
150
+
105 151
 // searchEntry : search an LDAP source if an entry (name, passwd) is valid and in the specific filter
106 152
 func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, string, string, string, bool, bool) {
107
-	l, err := ldapDial(ls)
153
+	l, err := dial(ls)
108 154
 	if err != nil {
109 155
 		log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
110 156
 		ls.Enabled = false
@@ -197,26 +243,3 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
197 243
 
198 244
 	return username_attr, name_attr, sn_attr, mail_attr, admin_attr, true
199 245
 }
200
-
201
-func bindUser(l *ldap.Conn, userDN, passwd string) error {
202
-	log.Trace("Binding with userDN: %s", userDN)
203
-	err := l.Bind(userDN, passwd)
204
-	if err != nil {
205
-		log.Debug("LDAP auth. failed for %s, reason: %v", userDN, err)
206
-		return err
207
-	}
208
-	log.Trace("Bound successfully with userDN: %s", userDN)
209
-	return err
210
-}
211
-
212
-func ldapDial(ls *Source) (*ldap.Conn, error) {
213
-	if ls.UseSSL {
214
-		log.Debug("Using TLS for LDAP without verifying: %v", ls.SkipVerify)
215
-		return ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port), &tls.Config{
216
-			ServerName:         ls.Host,
217
-			InsecureSkipVerify: ls.SkipVerify,
218
-		})
219
-	} else {
220
-		return ldap.Dial("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port))
221
-	}
222
-}

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


+ 21 - 0
public/js/gogs.js

@@ -612,6 +612,13 @@ function initAdmin() {
612 612
         });
613 613
     }
614 614
 
615
+    function onSecurityProtocolChange() {
616
+        if ($('#security_protocol').val() > 0) {
617
+            $('.has-tls').show();
618
+        } else {
619
+            $('.has-tls').hide();
620
+        }
621
+    }
615 622
 
616 623
     // New authentication
617 624
     if ($('.admin.new.authentication').length > 0) {
@@ -620,6 +627,7 @@ function initAdmin() {
620 627
             $('.dldap').hide();
621 628
             $('.smtp').hide();
622 629
             $('.pam').hide();
630
+            $('.has-tls').hide();
623 631
 
624 632
             var auth_type = $(this).val();
625 633
             switch (auth_type) {
@@ -628,6 +636,7 @@ function initAdmin() {
628 636
                     break;
629 637
                 case '3':     // SMTP
630 638
                     $('.smtp').show();
639
+                    $('.has-tls').show();
631 640
                     break;
632 641
                 case '4':     // PAM
633 642
                     $('.pam').show();
@@ -636,7 +645,19 @@ function initAdmin() {
636 645
                     $('.dldap').show();
637 646
                     break;
638 647
             }
648
+
649
+            if (auth_type == '2' || auth_type == '5') {
650
+                onSecurityProtocolChange()
651
+            }
639 652
         });
653
+        $('#security_protocol').change(onSecurityProtocolChange)
654
+    }
655
+    // Edit authentication
656
+    if ($('.admin.edit.authentication').length > 0) {
657
+        var auth_type = $('#auth_type').val();
658
+        if (auth_type == '2' || auth_type == '5') {
659
+            $('#security_protocol').change(onSecurityProtocolChange);
660
+        }
640 661
     }
641 662
 
642 663
     // Notice

+ 35 - 16
routers/admin/auths.go

@@ -41,17 +41,24 @@ func Authentications(ctx *context.Context) {
41 41
 	ctx.HTML(200, AUTHS)
42 42
 }
43 43
 
44
-type AuthSource struct {
44
+type dropdownItem struct {
45 45
 	Name string
46
-	Type models.LoginType
46
+	Type interface{}
47 47
 }
48 48
 
49
-var authSources = []AuthSource{
50
-	{models.LoginNames[models.LOGIN_LDAP], models.LOGIN_LDAP},
51
-	{models.LoginNames[models.LOGIN_DLDAP], models.LOGIN_DLDAP},
52
-	{models.LoginNames[models.LOGIN_SMTP], models.LOGIN_SMTP},
53
-	{models.LoginNames[models.LOGIN_PAM], models.LOGIN_PAM},
54
-}
49
+var (
50
+	authSources = []dropdownItem{
51
+		{models.LoginNames[models.LOGIN_LDAP], models.LOGIN_LDAP},
52
+		{models.LoginNames[models.LOGIN_DLDAP], models.LOGIN_DLDAP},
53
+		{models.LoginNames[models.LOGIN_SMTP], models.LOGIN_SMTP},
54
+		{models.LoginNames[models.LOGIN_PAM], models.LOGIN_PAM},
55
+	}
56
+	securityProtocols = []dropdownItem{
57
+		{models.SecurityProtocolNames[ldap.SECURITY_PROTOCOL_UNENCRYPTED], ldap.SECURITY_PROTOCOL_UNENCRYPTED},
58
+		{models.SecurityProtocolNames[ldap.SECURITY_PROTOCOL_LDAPS], ldap.SECURITY_PROTOCOL_LDAPS},
59
+		{models.SecurityProtocolNames[ldap.SECURITY_PROTOCOL_START_TLS], ldap.SECURITY_PROTOCOL_START_TLS},
60
+	}
61
+)
55 62
 
56 63
 func NewAuthSource(ctx *context.Context) {
57 64
 	ctx.Data["Title"] = ctx.Tr("admin.auths.new")
@@ -59,10 +66,12 @@ func NewAuthSource(ctx *context.Context) {
59 66
 	ctx.Data["PageIsAdminAuthentications"] = true
60 67
 
61 68
 	ctx.Data["type"] = models.LOGIN_LDAP
62
-	ctx.Data["CurTypeName"] = models.LoginNames[models.LOGIN_LDAP]
69
+	ctx.Data["CurrentTypeName"] = models.LoginNames[models.LOGIN_LDAP]
70
+	ctx.Data["CurrentSecurityProtocol"] = models.SecurityProtocolNames[ldap.SECURITY_PROTOCOL_UNENCRYPTED]
63 71
 	ctx.Data["smtp_auth"] = "PLAIN"
64 72
 	ctx.Data["is_active"] = true
65 73
 	ctx.Data["AuthSources"] = authSources
74
+	ctx.Data["SecurityProtocols"] = securityProtocols
66 75
 	ctx.Data["SMTPAuths"] = models.SMTPAuths
67 76
 	ctx.HTML(200, AUTH_NEW)
68 77
 }
@@ -73,7 +82,7 @@ func parseLDAPConfig(form auth.AuthenticationForm) *models.LDAPConfig {
73 82
 			Name:              form.Name,
74 83
 			Host:              form.Host,
75 84
 			Port:              form.Port,
76
-			UseSSL:            form.TLS,
85
+			SecurityProtocol:  ldap.SecurityProtocol(form.SecurityProtocol),
77 86
 			SkipVerify:        form.SkipVerify,
78 87
 			BindDN:            form.BindDN,
79 88
 			UserDN:            form.UserDN,
@@ -107,21 +116,21 @@ func NewAuthSourcePost(ctx *context.Context, form auth.AuthenticationForm) {
107 116
 	ctx.Data["PageIsAdmin"] = true
108 117
 	ctx.Data["PageIsAdminAuthentications"] = true
109 118
 
110
-	ctx.Data["CurTypeName"] = models.LoginNames[models.LoginType(form.Type)]
119
+	ctx.Data["CurrentTypeName"] = models.LoginNames[models.LoginType(form.Type)]
120
+	ctx.Data["CurrentSecurityProtocol"] = models.SecurityProtocolNames[ldap.SecurityProtocol(form.SecurityProtocol)]
111 121
 	ctx.Data["AuthSources"] = authSources
122
+	ctx.Data["SecurityProtocols"] = securityProtocols
112 123
 	ctx.Data["SMTPAuths"] = models.SMTPAuths
113 124
 
114
-	if ctx.HasError() {
115
-		ctx.HTML(200, AUTH_NEW)
116
-		return
117
-	}
118
-
125
+	hasTLS := false
119 126
 	var config core.Conversion
120 127
 	switch models.LoginType(form.Type) {
121 128
 	case models.LOGIN_LDAP, models.LOGIN_DLDAP:
122 129
 		config = parseLDAPConfig(form)
130
+		hasTLS = ldap.SecurityProtocol(form.SecurityProtocol) > ldap.SECURITY_PROTOCOL_UNENCRYPTED
123 131
 	case models.LOGIN_SMTP:
124 132
 		config = parseSMTPConfig(form)
133
+		hasTLS = true
125 134
 	case models.LOGIN_PAM:
126 135
 		config = &models.PAMConfig{
127 136
 			ServiceName: form.PAMServiceName,
@@ -130,6 +139,12 @@ func NewAuthSourcePost(ctx *context.Context, form auth.AuthenticationForm) {
130 139
 		ctx.Error(400)
131 140
 		return
132 141
 	}
142
+	ctx.Data["HasTLS"] = hasTLS
143
+
144
+	if ctx.HasError() {
145
+		ctx.HTML(200, AUTH_NEW)
146
+		return
147
+	}
133 148
 
134 149
 	if err := models.CreateSource(&models.LoginSource{
135 150
 		Type:      models.LoginType(form.Type),
@@ -152,6 +167,7 @@ func EditAuthSource(ctx *context.Context) {
152 167
 	ctx.Data["PageIsAdmin"] = true
153 168
 	ctx.Data["PageIsAdminAuthentications"] = true
154 169
 
170
+	ctx.Data["SecurityProtocols"] = securityProtocols
155 171
 	ctx.Data["SMTPAuths"] = models.SMTPAuths
156 172
 
157 173
 	source, err := models.GetLoginSourceByID(ctx.ParamsInt64(":authid"))
@@ -160,6 +176,8 @@ func EditAuthSource(ctx *context.Context) {
160 176
 		return
161 177
 	}
162 178
 	ctx.Data["Source"] = source
179
+	ctx.Data["HasTLS"] = source.HasTLS()
180
+
163 181
 	ctx.HTML(200, AUTH_EDIT)
164 182
 }
165 183
 
@@ -176,6 +194,7 @@ func EditAuthSourcePost(ctx *context.Context, form auth.AuthenticationForm) {
176 194
 		return
177 195
 	}
178 196
 	ctx.Data["Source"] = source
197
+	ctx.Data["HasTLS"] = source.HasTLS()
179 198
 
180 199
 	if ctx.HasError() {
181 200
 		ctx.HTML(200, AUTH_EDIT)

+ 1 - 1
templates/.VERSION

@@ -1 +1 @@
1
-0.9.36.0704
1
+0.9.37.0708

+ 16 - 3
templates/admin/auth/edit.tmpl

@@ -14,7 +14,7 @@
14 14
 						<input type="hidden" name="id" value="{{.Source.ID}}">
15 15
 						<div class="inline field">
16 16
 							<label>{{$.i18n.Tr "admin.auths.auth_type"}}</label>
17
-							<input type="hidden" name="type" value="{{.Source.Type}}">
17
+							<input type="hidden" id="auth_type" name="type" value="{{.Source.Type}}">
18 18
 							<span>{{.Source.TypeName}}</span>
19 19
 						</div>
20 20
 						<div class="required inline field {{if .Err_Name}}error{{end}}">
@@ -25,6 +25,19 @@
25 25
 						<!-- LDAP and DLDAP -->
26 26
 						{{if or .Source.IsLDAP .Source.IsDLDAP}}
27 27
 							{{ $cfg:=.Source.LDAP }}
28
+							<div class="inline required field {{if .Err_SecurityProtocol}}error{{end}}">
29
+								<label>{{.i18n.Tr "admin.auths.security_protocol"}}</label>
30
+								<div class="ui selection security-protocol dropdown">
31
+									<input type="hidden" id="security_protocol" name="security_protocol" value="{{$cfg.SecurityProtocol}}">
32
+									<div class="text">{{$cfg.SecurityProtocolName}}</div>
33
+									<i class="dropdown icon"></i>
34
+									<div class="menu">
35
+										{{range .SecurityProtocols}}
36
+											<div class="item" data-value="{{.Type}}">{{.Name}}</div>
37
+										{{end}}
38
+									</div>
39
+								</div>
40
+							</div>
28 41
 							<div class="required field">
29 42
 								<label for="host">{{.i18n.Tr "admin.auths.host"}}</label>
30 43
 								<input id="host" name="host" value="{{$cfg.Host}}" placeholder="e.g. mydomain.com" required>
@@ -129,13 +142,13 @@
129 142
 							</div>
130 143
 						{{end}}
131 144
 
132
-						<div class="inline field {{if not (or (or .Source.IsLDAP .Source.IsDLDAP) .Source.IsSMTP)}}hide{{end}}">
145
+						<div class="inline field {{if not .Source.IsSMTP}}hide{{end}}">
133 146
 							<div class="ui checkbox">
134 147
 								<label><strong>{{.i18n.Tr "admin.auths.enable_tls"}}</strong></label>
135 148
 								<input name="tls" type="checkbox" {{if .Source.UseTLS}}checked{{end}}>
136 149
 							</div>
137 150
 						</div>
138
-						<div class="inline field {{if not (or (or .Source.IsLDAP .Source.IsDLDAP) .Source.IsSMTP)}}hide{{end}}">
151
+						<div class="has-tls inline field {{if not .HasTLS}}hide{{end}}">
139 152
 							<div class="ui checkbox">
140 153
 								<label><strong>{{.i18n.Tr "admin.auths.skip_tls_verify"}}</strong></label>
141 154
 								<input name="skip_verify" type="checkbox" {{if .Source.SkipVerify}}checked{{end}}>

+ 16 - 3
templates/admin/auth/new.tmpl

@@ -16,7 +16,7 @@
16 16
 							<label>{{.i18n.Tr "admin.auths.auth_type"}}</label>
17 17
 							<div class="ui selection type dropdown">
18 18
 								<input type="hidden" id="auth_type" name="type" value="{{.type}}">
19
-								<div class="text">{{.CurTypeName}}</div>
19
+								<div class="text">{{.CurrentTypeName}}</div>
20 20
 								<i class="dropdown icon"></i>
21 21
 								<div class="menu">
22 22
 									{{range .AuthSources}}
@@ -32,6 +32,19 @@
32 32
 
33 33
 						<!-- LDAP and DLDAP -->
34 34
 						<div class="ldap dldap field {{if not (or (eq .type 2) (eq .type 5))}}hide{{end}}">
35
+							<div class="inline required field {{if .Err_SecurityProtocol}}error{{end}}">
36
+								<label>{{.i18n.Tr "admin.auths.security_protocol"}}</label>
37
+								<div class="ui selection security-protocol dropdown">
38
+									<input type="hidden" id="security_protocol" name="security_protocol" value="{{.security_protocol}}">
39
+									<div class="text">{{.CurrentSecurityProtocol}}</div>
40
+									<i class="dropdown icon"></i>
41
+									<div class="menu">
42
+										{{range .SecurityProtocols}}
43
+											<div class="item" data-value="{{.Type}}">{{.Name}}</div>
44
+										{{end}}
45
+									</div>
46
+								</div>
47
+							</div>
35 48
 							<div class="required field">
36 49
 								<label for="host">{{.i18n.Tr "admin.auths.host"}}</label>
37 50
 								<input id="host" name="host" value="{{.host}}" placeholder="e.g. mydomain.com">
@@ -126,13 +139,13 @@
126 139
 								<input name="attributes_in_bind" type="checkbox" {{if .attributes_in_bind}}checked{{end}}>
127 140
 							</div>
128 141
 						</div>
129
-						<div class="ldap dldap smtp inline field {{if not (or (or (eq .type 2) (eq .type 5)) (eq .type 3))}}hide{{end}}">
142
+						<div class="smtp inline field {{if not (eq .type 3)}}hide{{end}}">
130 143
 							<div class="ui checkbox">
131 144
 								<label><strong>{{.i18n.Tr "admin.auths.enable_tls"}}</strong></label>
132 145
 								<input name="tls" type="checkbox" {{if .tls}}checked{{end}}>
133 146
 							</div>
134 147
 						</div>
135
-						<div class="ldap dldap smtp inline field {{if not (or (or (eq .type 2) (eq .type 5)) (eq .type 3))}}hide{{end}}">
148
+						<div class="has-tls inline field {{if not .HasTLS}}hide{{end}}">
136 149
 							<div class="ui checkbox">
137 150
 								<label><strong>{{.i18n.Tr "admin.auths.skip_tls_verify"}}</strong></label>
138 151
 								<input name="skip_verify" type="checkbox" {{if .skip_verify}}checked{{end}}>