Kaynağa Gözat

Added LDAP simple auth support.

Sergio Benitez 9 yıl önce
ebeveyn
işleme
2d1db4bf05

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

@@ -814,6 +814,7 @@ auths.port = Port
 auths.bind_dn = Bind DN
 auths.bind_password = Bind Password
 auths.user_base = User Search Base
+auths.user_dn = User DN
 auths.attribute_name = First name attribute
 auths.attribute_surname = Surname attribute
 auths.attribute_mail = E-mail attribute

+ 54 - 58
models/login.go

@@ -27,6 +27,7 @@ const (
 	NOTYPE LoginType = iota
 	PLAIN
 	LDAP
+	DLDAP
 	SMTP
 	PAM
 )
@@ -38,9 +39,10 @@ var (
 )
 
 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.
@@ -106,6 +108,8 @@ func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
 	case "type":
 		switch LoginType((*val).(int64)) {
 		case LDAP:
+			fallthrough
+		case DLDAP:
 			source.Cfg = new(LDAPConfig)
 		case SMTP:
 			source.Cfg = new(SMTPConfig)
@@ -171,84 +175,74 @@ func DelLoginSource(source *LoginSource) error {
 
 // UserSignIn validates user name and password.
 func UserSignIn(uname, passwd string) (*User, error) {
-	u := new(User)
+	var u *User
 	if strings.Contains(uname, "@") {
 		u = &User{Email: uname}
 	} else {
 		u = &User{LowerName: strings.ToLower(uname)}
 	}
 
-	has, err := x.Get(u)
+	userExists, err := x.Get(u)
 	if err != nil {
 		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}
+		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
 	}
 
-	switch u.LoginType {
+	switch source.Type {
 	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:
-		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:
-		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
 }
 
@@ -256,8 +250,10 @@ func UserSignIn(uname, passwd string) (*User, error) {
 // Create a local user if success
 // Return the same LoginUserPlain semantic
 // 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 {
 		// User not in LDAP, do nothing
 		return nil, ErrUserNotExist{0, name}
@@ -276,8 +272,8 @@ func LoginUserLdapSource(u *User, name, passwd string, sourceId int64, cfg *LDAP
 		LowerName:   strings.ToLower(name),
 		Name:        name,
 		FullName:    fn + " " + sn,
-		LoginType:   LDAP,
-		LoginSource: sourceId,
+		LoginType:   source.Type,
+		LoginSource: source.ID,
 		LoginName:   name,
 		Passwd:      passwd,
 		Email:       mail,

+ 1 - 0
modules/auth/auth_form.go

@@ -19,6 +19,7 @@ type AuthenticationForm struct {
 	BindDN            string `form:"bind_dn"`
 	BindPassword      string
 	UserBase          string
+	UserDN            string `form:"user_dn"`
 	AttributeName     string
 	AttributeSurname  string
 	AttributeMail     string

+ 20 - 5
modules/auth/ldap/ldap.go

@@ -22,6 +22,7 @@ type Ldapsource struct {
 	BindDN           string // DN to bind with
 	BindPassword     string // Bind DN password
 	UserBase         string // Base search path for users
+	UserDN           string // Template for the DN of the user for simple auth
 	AttributeName    string // First name attribute
 	AttributeSurname string // Surname 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
-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)
@@ -112,7 +122,12 @@ func (ls Ldapsource) SearchEntry(name, passwd string) (string, string, string, b
 		log.Error(4, "LDAP Search failed unexpectedly! (%v)", err)
 		return "", "", "", false, false
 	} 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
 	}
 

Dosya farkı çok büyük olduğundan ihmal edildi
+ 112 - 112
modules/bindata/bindata.go


+ 14 - 18
public/ng/js/gogs.js

@@ -57,10 +57,10 @@ var Gogs = {};
     });
     $.fn.extend({
         toggleHide: function () {
-            $(this).addClass("hidden");
+            $(this).each(function(n, v) { $(v).addClass("hidden"); });
         },
         toggleShow: function () {
-            $(this).removeClass("hidden");
+            $(this).each(function(n, v) { $(v).removeClass("hidden"); });
         },
         toggleAjax: function (successCallback, errorCallback) {
             var url = $(this).data("ajax");
@@ -775,24 +775,20 @@ function initAdmin() {
         $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 () {
         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.

+ 8 - 2
routers/admin/auths.go

@@ -61,6 +61,8 @@ func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
 	var u core.Conversion
 	switch models.LoginType(form.Type) {
 	case models.LDAP:
+	  fallthrough
+	case models.DLDAP:
 		u = &models.LDAPConfig{
 			Ldapsource: ldap.Ldapsource{
 				Name:             form.Name,
@@ -68,13 +70,14 @@ func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
 				Port:             form.Port,
 				UseSSL:           form.UseSSL,
 				BindDN:           form.BindDN,
+				UserDN:           form.UserDN,
 				BindPassword:     form.BindPassword,
 				UserBase:         form.UserBase,
-				Filter:           form.Filter,
-				AdminFilter:      form.AdminFilter,
 				AttributeName:    form.AttributeName,
 				AttributeSurname: form.AttributeSurname,
 				AttributeMail:    form.AttributeMail,
+				Filter:           form.Filter,
+				AdminFilter:      form.AdminFilter,
 				Enabled:          true,
 			},
 		}
@@ -149,6 +152,8 @@ func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
 	var config core.Conversion
 	switch models.LoginType(form.Type) {
 	case models.LDAP:
+	  fallthrough
+	case models.DLDAP:
 		config = &models.LDAPConfig{
 			Ldapsource: ldap.Ldapsource{
 				Name:             form.Name,
@@ -156,6 +161,7 @@ func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
 				Port:             form.Port,
 				UseSSL:           form.UseSSL,
 				BindDN:           form.BindDN,
+				UserDN:           form.UserDN,
 				BindPassword:     form.BindPassword,
 				UserBase:         form.UserBase,
 				AttributeName:    form.AttributeName,

+ 13 - 4
templates/admin/auth/edit.tmpl

@@ -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 />
                                 </div>
 
-                                {{if eq $type 2}}
+                                {{if eq $type 2 3}}
                                 <div class="field">
                                     <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 />
@@ -43,6 +43,7 @@
                                     <label for="use_ssl">{{.i18n.Tr "admin.auths.enable_tls"}}</label>
                                     <input name="use_ssl" type="checkbox" {{if .Source.LDAP.UseSSL}}checked{{end}}>
                                 </div>
+                                {{if eq $type 2}}
                                 <div class="field">
                                     <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}}" />
@@ -55,6 +56,13 @@
                                     <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}}" />
                                 </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">
                                     <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}}" />
@@ -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}}" />
                                 </div>
 
-                                {{else if eq $type 3}}
+
+                                {{else if eq $type 4}}
                                 <div class="field">
                                     <label class="req">{{.i18n.Tr "admin.auths.smtp_auth"}}</label>
                                     <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}}" />
                                 </div>
 
-                                {{else if eq $type 4}}
+                                {{else if eq $type 5}}
                                 <div class="field">
                                     <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}}" />
@@ -104,7 +113,7 @@
                                 {{end}}
 
                                 <div class="field">
-                                    {{if eq $type 3}}
+                                    {{if eq $type 4}}
                                     <label></label>
                                     <input name="tls" type="checkbox" {{if .Source.SMTP.TLS}}checked{{end}}>
                                     <strong>{{.i18n.Tr "admin.auths.enable_tls"}}</strong>

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

@@ -26,48 +26,52 @@
                                     <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 />
                                 </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>
                                         <input class="ipt ipt-large ipt-radius {{if .Err_Host}}ipt-error{{end}}" id="host" name="host" value="{{.host}}" />
                                     </div>
-                                    <div class="field">
+                                    <div class="dldap ldap field">
                                         <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}}" />
                                     </div>
-                                    <div class="field">
+                                    <div class="dldap ldap field">
                                         <label for="use_ssl">{{.i18n.Tr "admin.auths.enable_tls"}}</label>
                                         <input name="use_ssl" type="checkbox" {{if .use_ssl}}checked{{end}}>
                                     </div>
-                                    <div class="field">
+                                    <div class="ldap field">
                                         <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}}" />
                                     </div>
-                                    <div class="field">
+                                    <div class="ldap field">
                                         <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}}" />
                                     </div>
-                                    <div class="field">
+                                    <div class="ldap field">
                                         <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}}" />
                                     </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>
                                         <input class="ipt ipt-large ipt-radius {{if .Err_Filter}}ipt-error{{end}}" id="filter" name="filter" value="{{.filter}}" />
                                     </div>
-                                    <div class="field">
+                                    <div class="dldap ldap field">
                                         <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}}" />
                                     </div>
-                                    <div class="field">
+                                    <div class="dldap ldap field">
                                         <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}}" />
                                     </div>
-                                    <div class="field">
+                                    <div class="dldap ldap field">
                                         <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}}" />
                                     </div>
-                                    <div class="field">
+                                    <div class="dldap ldap field">
                                         <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}}" />
                                     </div>

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor