mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 09:44:21 +00:00 
			
		
		
		
	Significantly enhanced LDAP support in Gogs.
This commit is contained in:
		@@ -663,8 +663,6 @@ auths.auth_name=Име на удостоверяването
 | 
			
		||||
auths.domain=Домейн
 | 
			
		||||
auths.host=Хост
 | 
			
		||||
auths.port=Порт
 | 
			
		||||
auths.base_dn=Основен DN
 | 
			
		||||
auths.attribute_username=Атрибут на потребителско име
 | 
			
		||||
auths.attribute_name=Атрибут име
 | 
			
		||||
auths.attribute_surname=Атрибут фамилия
 | 
			
		||||
auths.attribute_mail=E-Mail атрибут
 | 
			
		||||
 
 | 
			
		||||
@@ -722,8 +722,6 @@ auths.auth_name=Authentifizierungsname
 | 
			
		||||
auths.domain=Domain
 | 
			
		||||
auths.host=Host
 | 
			
		||||
auths.port=Port
 | 
			
		||||
auths.base_dn=Base DN
 | 
			
		||||
auths.attribute_username=Benutzername Attribut
 | 
			
		||||
auths.attribute_name=Vorname Attribut
 | 
			
		||||
auths.attribute_surname=Nachname Attribut
 | 
			
		||||
auths.attribute_mail=E-Mail Attribut
 | 
			
		||||
 
 | 
			
		||||
@@ -722,12 +722,13 @@ auths.auth_name = Authorization Name
 | 
			
		||||
auths.domain = Domain
 | 
			
		||||
auths.host = Host
 | 
			
		||||
auths.port = Port
 | 
			
		||||
auths.base_dn = Base DN
 | 
			
		||||
auths.attribute_username = Username attribute
 | 
			
		||||
auths.bind_dn = Bind DN
 | 
			
		||||
auths.bind_password = Bind Password
 | 
			
		||||
auths.user_base = User Search Base
 | 
			
		||||
auths.attribute_name = First name attribute
 | 
			
		||||
auths.attribute_surname = Surname attribute
 | 
			
		||||
auths.attribute_mail = E-mail attribute
 | 
			
		||||
auths.filter = Search Filter
 | 
			
		||||
auths.filter = User Filter
 | 
			
		||||
auths.ms_ad_sa = Ms Ad SA
 | 
			
		||||
auths.smtp_auth = SMTP Authorization Type
 | 
			
		||||
auths.smtphost = SMTP Host
 | 
			
		||||
 
 | 
			
		||||
@@ -663,13 +663,10 @@ auths.auth_name=Nombre de Autorización
 | 
			
		||||
auths.domain=Dominio
 | 
			
		||||
auths.host=Host
 | 
			
		||||
auths.port=Puerto
 | 
			
		||||
auths.base_dn=Base DN
 | 
			
		||||
auths.attribute_username=Atributo username
 | 
			
		||||
auths.attribute_name=Atributo nombre
 | 
			
		||||
auths.attribute_surname=Atributo apellido
 | 
			
		||||
auths.attribute_mail=Atributo correo electrónico
 | 
			
		||||
auths.filter=Filtro de Búsqueda
 | 
			
		||||
auths.ms_ad_sa=Ms Ad SA
 | 
			
		||||
auths.smtp_auth=Tipo de Autorización SMTP
 | 
			
		||||
auths.smtphost=SMTP Host
 | 
			
		||||
auths.smtpport=Puerto SMTP
 | 
			
		||||
 
 | 
			
		||||
@@ -722,8 +722,6 @@ auths.auth_name=Nom d'Autorisation
 | 
			
		||||
auths.domain=Domaine
 | 
			
		||||
auths.host=Hôte
 | 
			
		||||
auths.port=Port
 | 
			
		||||
auths.base_dn=Base DN (Nom Distingué)
 | 
			
		||||
auths.attribute_username=Attribut du nom d'utilisateur
 | 
			
		||||
auths.attribute_name=Attribut du prénom
 | 
			
		||||
auths.attribute_surname=Attribut du nom de famille
 | 
			
		||||
auths.attribute_mail=Attribut de l'e-mail
 | 
			
		||||
 
 | 
			
		||||
@@ -663,8 +663,6 @@ auths.auth_name=Nome Autorizzazione
 | 
			
		||||
auths.domain=Dominio
 | 
			
		||||
auths.host=Host
 | 
			
		||||
auths.port=Porta
 | 
			
		||||
auths.base_dn=Base DN
 | 
			
		||||
auths.attribute_username=Attributo Nome Utente
 | 
			
		||||
auths.attribute_name=Attributo Nome
 | 
			
		||||
auths.attribute_surname=Attributo Cognome
 | 
			
		||||
auths.attribute_mail=Attributo Email
 | 
			
		||||
 
 | 
			
		||||
@@ -663,8 +663,6 @@ auths.auth_name=認証名
 | 
			
		||||
auths.domain=ドメイン
 | 
			
		||||
auths.host=ホスト
 | 
			
		||||
auths.port=ポート
 | 
			
		||||
auths.base_dn=ベースのドメイン名
 | 
			
		||||
auths.attribute_username=ユーザー名属性
 | 
			
		||||
auths.attribute_name=名前属性
 | 
			
		||||
auths.attribute_surname=名字属性
 | 
			
		||||
auths.attribute_mail=Eメール属性
 | 
			
		||||
 
 | 
			
		||||
@@ -663,8 +663,6 @@ auths.auth_name=Autorizācijas nosaukums
 | 
			
		||||
auths.domain=Domēns
 | 
			
		||||
auths.host=Resursdators
 | 
			
		||||
auths.port=Ports
 | 
			
		||||
auths.base_dn=Pamata DN
 | 
			
		||||
auths.attribute_username=Username attribute
 | 
			
		||||
auths.attribute_name=First name attribute
 | 
			
		||||
auths.attribute_surname=Surname attribute
 | 
			
		||||
auths.attribute_mail=E-mail attribute
 | 
			
		||||
 
 | 
			
		||||
@@ -663,8 +663,6 @@ auths.auth_name=Autorisatienaam
 | 
			
		||||
auths.domain=Domein
 | 
			
		||||
auths.host=Host
 | 
			
		||||
auths.port=Poort
 | 
			
		||||
auths.base_dn=Base DN
 | 
			
		||||
auths.attribute_username=Gebruikersnaam attribuut
 | 
			
		||||
auths.attribute_name=Voornaam attribuut
 | 
			
		||||
auths.attribute_surname=Achternaam attribuut
 | 
			
		||||
auths.attribute_mail=E-mail attribuut
 | 
			
		||||
 
 | 
			
		||||
@@ -663,8 +663,6 @@ auths.auth_name=Nazwa autoryzacji
 | 
			
		||||
auths.domain=Domena
 | 
			
		||||
auths.host=Host
 | 
			
		||||
auths.port=Port
 | 
			
		||||
auths.base_dn=Base DN
 | 
			
		||||
auths.attribute_username=Atrybut username
 | 
			
		||||
auths.attribute_name=Atrybut imienia
 | 
			
		||||
auths.attribute_surname=Atrybut nazwiska
 | 
			
		||||
auths.attribute_mail=Atrybut email
 | 
			
		||||
 
 | 
			
		||||
@@ -663,8 +663,6 @@ auths.auth_name=Nome da Autorização
 | 
			
		||||
auths.domain=Domínio
 | 
			
		||||
auths.host=Host
 | 
			
		||||
auths.port=Porta
 | 
			
		||||
auths.base_dn=Base DN
 | 
			
		||||
auths.attribute_username=Atributo nome de usuário
 | 
			
		||||
auths.attribute_name=Atributo primeiro nome
 | 
			
		||||
auths.attribute_surname=Atributo sobrenome
 | 
			
		||||
auths.attribute_mail=Atributo e-mail
 | 
			
		||||
 
 | 
			
		||||
@@ -663,8 +663,6 @@ auths.auth_name=Название авторизации
 | 
			
		||||
auths.domain=Домен
 | 
			
		||||
auths.host=Хост
 | 
			
		||||
auths.port=Порт
 | 
			
		||||
auths.base_dn=Base DN
 | 
			
		||||
auths.attribute_username=Username attribute
 | 
			
		||||
auths.attribute_name=First name attribute
 | 
			
		||||
auths.attribute_surname=Surname attribute
 | 
			
		||||
auths.attribute_mail=E-mail attribute
 | 
			
		||||
 
 | 
			
		||||
@@ -722,8 +722,6 @@ auths.auth_name=授权名称
 | 
			
		||||
auths.domain=域名
 | 
			
		||||
auths.host=主机地址
 | 
			
		||||
auths.port=主机端口
 | 
			
		||||
auths.base_dn=Base DN
 | 
			
		||||
auths.attribute_username=用户名属性
 | 
			
		||||
auths.attribute_name=名字属性
 | 
			
		||||
auths.attribute_surname=姓氏属性
 | 
			
		||||
auths.attribute_mail=邮箱属性
 | 
			
		||||
 
 | 
			
		||||
@@ -663,8 +663,6 @@ auths.auth_name=授權名稱
 | 
			
		||||
auths.domain=域名
 | 
			
		||||
auths.host=主機地址
 | 
			
		||||
auths.port=主機端口
 | 
			
		||||
auths.base_dn=Base DN
 | 
			
		||||
auths.attribute_username=用戶名屬性
 | 
			
		||||
auths.attribute_name=名子屬性
 | 
			
		||||
auths.attribute_surname=姓氏屬性
 | 
			
		||||
auths.attribute_mail=電子郵箱屬性
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,6 @@ import (
 | 
			
		||||
	"github.com/gogits/gogs/modules/auth/ldap"
 | 
			
		||||
	"github.com/gogits/gogs/modules/auth/pam"
 | 
			
		||||
	"github.com/gogits/gogs/modules/log"
 | 
			
		||||
	"github.com/gogits/gogs/modules/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type LoginType int
 | 
			
		||||
@@ -258,18 +257,19 @@ func UserSignIn(uname, passwd string) (*User, error) {
 | 
			
		||||
// 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) {
 | 
			
		||||
	name, fn, sn, mail, logged := cfg.Ldapsource.SearchEntry(name, passwd)
 | 
			
		||||
	fn, sn, mail, logged := cfg.Ldapsource.SearchEntry(name, passwd)
 | 
			
		||||
	if !logged {
 | 
			
		||||
		// User not in LDAP, do nothing
 | 
			
		||||
		return nil, ErrUserNotExist{u.Id, u.Name}
 | 
			
		||||
		return nil, ErrUserNotExist{0, name}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !autoRegister {
 | 
			
		||||
		return u, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Fallback.
 | 
			
		||||
	if len(mail) == 0 {
 | 
			
		||||
		mail = uuid.NewV4().String() + "@localhost"
 | 
			
		||||
		mail = fmt.Sprintf("%s@localhost", name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	u = &User{
 | 
			
		||||
 
 | 
			
		||||
@@ -13,17 +13,16 @@ type AuthenticationForm struct {
 | 
			
		||||
	ID                int64 `form:"id"`
 | 
			
		||||
	Type              int
 | 
			
		||||
	Name              string `binding:"Required;MaxSize(50)"`
 | 
			
		||||
	Domain            string
 | 
			
		||||
	Host              string
 | 
			
		||||
	Port              int
 | 
			
		||||
	UseSSL            bool   `form:"usessl"`
 | 
			
		||||
	BaseDN            string `form:"base_dn"`
 | 
			
		||||
	AttributeUsername string
 | 
			
		||||
	UseSSL            bool   `form:"use_ssl"`
 | 
			
		||||
	BindDN            string `form:"bind_dn"`
 | 
			
		||||
	BindPassword      string
 | 
			
		||||
	UserBase          string
 | 
			
		||||
	AttributeName     string
 | 
			
		||||
	AttributeSurname  string
 | 
			
		||||
	AttributeMail     string
 | 
			
		||||
	Filter            string
 | 
			
		||||
	MsAdSA            string `form:"ms_ad_sa"`
 | 
			
		||||
	IsActived         bool
 | 
			
		||||
	SMTPAuth          string `form:"smtp_auth"`
 | 
			
		||||
	SMTPHost          string `form:"smtp_host"`
 | 
			
		||||
 
 | 
			
		||||
@@ -1,43 +1,64 @@
 | 
			
		||||
LDAP authentication
 | 
			
		||||
===================
 | 
			
		||||
Gogs LDAP Authentication Module
 | 
			
		||||
===============================
 | 
			
		||||
 | 
			
		||||
## Goal
 | 
			
		||||
## About
 | 
			
		||||
 | 
			
		||||
Authenticat user against LDAP directories
 | 
			
		||||
 | 
			
		||||
It will bind with the user's login/pasword and query attributs ("mail" for instance) in a pool of directory servers
 | 
			
		||||
 | 
			
		||||
The first OK wins.
 | 
			
		||||
 | 
			
		||||
If there's connection error, the server will be disabled and won't be checked again
 | 
			
		||||
This authentication module attempts to authorize and authenticate a user
 | 
			
		||||
against an LDAP server. Like most LDAP authentication systems, this module does
 | 
			
		||||
this in two steps. First, it queries the LDAP server using a Bind DN and
 | 
			
		||||
searches for the user that is attempting to sign in. If the user is found, the
 | 
			
		||||
module attempts to bind to the server using the user's supplied credentials. If
 | 
			
		||||
this succeeds, the user has been authenticated, and his account information is
 | 
			
		||||
retrieved and passed to the Gogs login infrastructure.
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
In the [security] section, set
 | 
			
		||||
>  LDAP_AUTH = true
 | 
			
		||||
To use this module, add an LDAP authentication source via the Authentications
 | 
			
		||||
section in the admin panel. The fields should be set as follows:
 | 
			
		||||
 | 
			
		||||
then for each LDAP source, set
 | 
			
		||||
Authorization Name (required)
 | 
			
		||||
	A name to assign to the new method of authorization.
 | 
			
		||||
 | 
			
		||||
> [LdapSource-someuniquename]
 | 
			
		||||
> name=canonicalName
 | 
			
		||||
> host=hostname-or-ip
 | 
			
		||||
> port=3268	# or regular LDAP port
 | 
			
		||||
> # the following settings depend highly how you've configured your AD
 | 
			
		||||
> basedn=dc=ACME,dc=COM
 | 
			
		||||
> MSADSAFORMAT=%s@ACME.COM
 | 
			
		||||
> filter=(&(objectClass=user)(sAMAccountName=%s))
 | 
			
		||||
Host (required)
 | 
			
		||||
	The address where the LDAP server can be reached.
 | 
			
		||||
	Example: mydomain.com
 | 
			
		||||
 | 
			
		||||
### Limitation
 | 
			
		||||
Port (required)
 | 
			
		||||
	The port to use when connecting to the server.
 | 
			
		||||
	Example: 636
 | 
			
		||||
 | 
			
		||||
Only tested on an MS 2008R2 DC, using global catalog (TCP/3268)
 | 
			
		||||
Enable TLS Encryption (optional)
 | 
			
		||||
	Whether to use TLS when connecting to the LDAP server.
 | 
			
		||||
 | 
			
		||||
This MSAD is a mess.
 | 
			
		||||
Bind DN (optional)
 | 
			
		||||
	The DN to bind to the LDAP server with when searching for the user.
 | 
			
		||||
	This may be left blank to perform an anonymous search.
 | 
			
		||||
	Example: cn=Search,dc=mydomain,dc=com
 | 
			
		||||
 | 
			
		||||
The way how one checks the directory (CN, DN etc...) may be highly depending local custom configuration
 | 
			
		||||
Bind Password (optional)
 | 
			
		||||
	The password for the Bind DN specified above, if any.
 | 
			
		||||
 | 
			
		||||
### Todo
 | 
			
		||||
* Define a timeout per server
 | 
			
		||||
* Check servers marked as "Disabled" when they'll come back online
 | 
			
		||||
* Find a more flexible way to define filter/MSADSAFORMAT/Attributes etc... maybe text/template ?
 | 
			
		||||
* Check OpenLDAP server
 | 
			
		||||
* SSL support ?
 | 
			
		||||
User Search Base (required)
 | 
			
		||||
	The LDAP base at which user accounts will be searched for.
 | 
			
		||||
	Example: ou=Users,dc=mydomain,dc=com
 | 
			
		||||
 | 
			
		||||
User Filter (required)
 | 
			
		||||
	An LDAP filter declaring how to find the user record that is attempting
 | 
			
		||||
	to authenticate. The '%s' matching parameter will be substituted with
 | 
			
		||||
	the user's username.
 | 
			
		||||
	Example: (&(objectClass=posixAccount)(uid=%s))
 | 
			
		||||
 | 
			
		||||
First name attribute (optional)
 | 
			
		||||
	The attribute of the user's LDAP record containing the user's first
 | 
			
		||||
	name. This will be used to populate their account information.
 | 
			
		||||
	Example: givenName
 | 
			
		||||
 | 
			
		||||
Surname name attribute (optional)
 | 
			
		||||
	The attribute of the user's LDAP record containing the user's surname
 | 
			
		||||
	This will be used to populate their account information.
 | 
			
		||||
	Example: sn
 | 
			
		||||
 | 
			
		||||
E-mail attribute (required)
 | 
			
		||||
	The attribute of the user's LDAP record containing the user's email
 | 
			
		||||
	address. This will be used to populate their account information.
 | 
			
		||||
	Example: mail
 | 
			
		||||
 
 | 
			
		||||
@@ -19,82 +19,114 @@ type Ldapsource struct {
 | 
			
		||||
	Host              string // LDAP host
 | 
			
		||||
	Port              int    // port number
 | 
			
		||||
	UseSSL            bool   // Use SSL
 | 
			
		||||
	BaseDN            string // Base DN
 | 
			
		||||
	AttributeUsername string // Username attribute
 | 
			
		||||
	BindDN            string // DN to bind with
 | 
			
		||||
	BindPassword      string // Bind DN password
 | 
			
		||||
	UserBase          string // Base search path for users
 | 
			
		||||
	AttributeName     string // First name attribute
 | 
			
		||||
	AttributeSurname  string // Surname attribute
 | 
			
		||||
	AttributeMail     string // E-mail attribute
 | 
			
		||||
	Filter            string // Query filter to validate entry
 | 
			
		||||
	MsAdSAFormat      string // in the case of MS AD Simple Authen, the format to use (see: http://msdn.microsoft.com/en-us/library/cc223499.aspx)
 | 
			
		||||
	Enabled           bool   // if this source is disabled
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Global LDAP directory pool
 | 
			
		||||
var (
 | 
			
		||||
	Authensource []Ldapsource
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Add a new source (LDAP directory) to the global pool
 | 
			
		||||
func AddSource(name string, host string, port int, usessl bool, basedn string, attribcn string, attribname string, attribsn string, attribmail string, filter string, msadsaformat string) {
 | 
			
		||||
	ldaphost := Ldapsource{name, host, port, usessl, basedn, attribcn, attribname, attribsn, attribmail, filter, msadsaformat, true}
 | 
			
		||||
	Authensource = append(Authensource, ldaphost)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//LoginUser : try to login an user to LDAP sources, return requested (attribute,true) if ok, ("",false) other wise
 | 
			
		||||
//First match wins
 | 
			
		||||
//Returns first attribute if exists
 | 
			
		||||
func LoginUser(name, passwd string) (cn, fn, sn, mail string, r bool) {
 | 
			
		||||
	r = false
 | 
			
		||||
	for _, ls := range Authensource {
 | 
			
		||||
		cn, fn, sn, mail, r = ls.SearchEntry(name, passwd)
 | 
			
		||||
		if r {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// searchEntry : search an LDAP source if an entry (name, passwd) is valide and in the specific filter
 | 
			
		||||
func (ls Ldapsource) SearchEntry(name, passwd string) (string, string, string, string, bool) {
 | 
			
		||||
func (ls Ldapsource) FindUserDN(name string) (userDN string, success bool) {
 | 
			
		||||
	userDN = ""
 | 
			
		||||
	success = false
 | 
			
		||||
	l, err := ldapDial(ls)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
 | 
			
		||||
		ls.Enabled = false
 | 
			
		||||
		return "", "", "", "", false
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer l.Close()
 | 
			
		||||
	log.Trace("Search for LDAP user: %s", name)
 | 
			
		||||
	if ls.BindDN != "" && ls.BindPassword != "" {
 | 
			
		||||
		err = l.Bind(ls.BindDN, ls.BindPassword)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Debug("Failed to bind as BindDN: %s, %s", ls.BindDN, err.Error())
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		log.Trace("Bound as BindDN %s", ls.BindDN)
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Trace("Proceeding with anonymous LDAP search.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// A search for the user.
 | 
			
		||||
	userFilter := fmt.Sprintf(ls.Filter, name)
 | 
			
		||||
	log.Trace("Searching using filter %s", userFilter)
 | 
			
		||||
	search := ldap.NewSearchRequest(
 | 
			
		||||
		ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0,
 | 
			
		||||
		false, userFilter, []string{}, nil)
 | 
			
		||||
 | 
			
		||||
	// Ensure we found a user
 | 
			
		||||
	sr, err := l.Search(search)
 | 
			
		||||
	if err != nil || len(sr.Entries) < 1 {
 | 
			
		||||
		log.Debug("Failed search using filter %s: %s", userFilter, err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	} else if len(sr.Entries) > 1 {
 | 
			
		||||
		log.Debug("Filter '%s' returned more than one user.", userFilter)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	userDN = sr.Entries[0].DN
 | 
			
		||||
	if userDN == "" {
 | 
			
		||||
		log.Error(4, "LDAP search was succesful, but found no DN!")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	success = true
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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) {
 | 
			
		||||
	userDN, found := ls.FindUserDN(name)
 | 
			
		||||
	if !found {
 | 
			
		||||
		return "", "", "", false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l, err := ldapDial(ls)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
 | 
			
		||||
		ls.Enabled = false
 | 
			
		||||
		return "", "", "", false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer l.Close()
 | 
			
		||||
 | 
			
		||||
	nx := fmt.Sprintf(ls.MsAdSAFormat, name)
 | 
			
		||||
	err = l.Bind(nx, passwd)
 | 
			
		||||
	log.Trace("Binding with userDN: %s", userDN)
 | 
			
		||||
	err = l.Bind(userDN, passwd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Debug("LDAP Authan failed for %s, reason: %s", nx, err.Error())
 | 
			
		||||
		return "", "", "", "", false
 | 
			
		||||
		log.Debug("LDAP auth. failed for %s, reason: %s", userDN, err.Error())
 | 
			
		||||
		return "", "", "", false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Trace("Bound successfully with userDN: %s", userDN)
 | 
			
		||||
	userFilter := fmt.Sprintf(ls.Filter, name)
 | 
			
		||||
	search := ldap.NewSearchRequest(
 | 
			
		||||
		ls.BaseDN,
 | 
			
		||||
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
 | 
			
		||||
		fmt.Sprintf(ls.Filter, name),
 | 
			
		||||
		[]string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail},
 | 
			
		||||
		userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
 | 
			
		||||
		[]string{ls.AttributeName, ls.AttributeSurname, ls.AttributeMail},
 | 
			
		||||
		nil)
 | 
			
		||||
 | 
			
		||||
	sr, err := l.Search(search)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Debug("LDAP Authen OK but not in filter %s", name)
 | 
			
		||||
		return "", "", "", "", false
 | 
			
		||||
		log.Error(4, "LDAP Search failed unexpectedly! (%s)", err.Error())
 | 
			
		||||
		return "", "", "", false
 | 
			
		||||
	} else if len(sr.Entries) < 1 {
 | 
			
		||||
		log.Error(4, "LDAP Search failed unexpectedly! (0 entries)")
 | 
			
		||||
		return "", "", "", false
 | 
			
		||||
	}
 | 
			
		||||
	log.Debug("LDAP Authen OK: %s", name)
 | 
			
		||||
	if len(sr.Entries) > 0 {
 | 
			
		||||
		cn := sr.Entries[0].GetAttributeValue(ls.AttributeUsername)
 | 
			
		||||
		name := sr.Entries[0].GetAttributeValue(ls.AttributeName)
 | 
			
		||||
		sn := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
 | 
			
		||||
		mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
 | 
			
		||||
		return cn, name, sn, mail, true
 | 
			
		||||
	}
 | 
			
		||||
	return "", "", "", "", true
 | 
			
		||||
 | 
			
		||||
	name_attr := sr.Entries[0].GetAttributeValue(ls.AttributeName)
 | 
			
		||||
	sn_attr := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
 | 
			
		||||
	mail_attr := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
 | 
			
		||||
	return name_attr, sn_attr, mail_attr, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ldapDial(ls Ldapsource) (*ldap.Conn, error) {
 | 
			
		||||
	if ls.UseSSL {
 | 
			
		||||
		log.Debug("Using TLS for LDAP")
 | 
			
		||||
		return ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port), nil)
 | 
			
		||||
	} else {
 | 
			
		||||
		return ldap.Dial("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port))
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +0,0 @@
 | 
			
		||||
package ldap
 | 
			
		||||
 | 
			
		||||
// import (
 | 
			
		||||
// 	"fmt"
 | 
			
		||||
// 	"testing"
 | 
			
		||||
// )
 | 
			
		||||
 | 
			
		||||
// var ldapServer = "ldap.itd.umich.edu"
 | 
			
		||||
// var ldapPort = 389
 | 
			
		||||
// var baseDN = "dc=umich,dc=edu"
 | 
			
		||||
// var filter = []string{
 | 
			
		||||
// 	"(cn=cis-fac)",
 | 
			
		||||
// 	"(&(objectclass=rfc822mailgroup)(cn=*Computer*))",
 | 
			
		||||
// 	"(&(objectclass=rfc822mailgroup)(cn=*Mathematics*))"}
 | 
			
		||||
// var attributes = []string{
 | 
			
		||||
// 	"cn",
 | 
			
		||||
// 	"description"}
 | 
			
		||||
// var msadsaformat = ""
 | 
			
		||||
 | 
			
		||||
// func TestLDAP(t *testing.T) {
 | 
			
		||||
// 	AddSource("test", ldapServer, ldapPort, baseDN, attributes, filter, msadsaformat)
 | 
			
		||||
// 	user, err := LoginUserLdap("xiaolunwen", "")
 | 
			
		||||
// 	if err != nil {
 | 
			
		||||
// 		t.Error(err)
 | 
			
		||||
// 		return
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	fmt.Println(user)
 | 
			
		||||
// }
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -63,18 +63,18 @@ 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,
 | 
			
		||||
				BaseDN:            form.BaseDN,
 | 
			
		||||
				AttributeUsername: form.AttributeUsername,
 | 
			
		||||
				BindDN:            form.BindDN,
 | 
			
		||||
				BindPassword:      form.BindPassword,
 | 
			
		||||
				UserBase:          form.UserBase,
 | 
			
		||||
				Filter:            form.Filter,
 | 
			
		||||
				AttributeName:     form.AttributeName,
 | 
			
		||||
				AttributeSurname:  form.AttributeSurname,
 | 
			
		||||
				AttributeMail:     form.AttributeMail,
 | 
			
		||||
				Filter:            form.Filter,
 | 
			
		||||
				MsAdSAFormat:      form.MsAdSA,
 | 
			
		||||
				Enabled:           true,
 | 
			
		||||
				Name:              form.Name,
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
	case models.SMTP:
 | 
			
		||||
@@ -149,18 +149,18 @@ 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,
 | 
			
		||||
				BaseDN:            form.BaseDN,
 | 
			
		||||
				AttributeUsername: form.AttributeUsername,
 | 
			
		||||
				BindDN:            form.BindDN,
 | 
			
		||||
				BindPassword:      form.BindPassword,
 | 
			
		||||
				UserBase:          form.UserBase,
 | 
			
		||||
				AttributeName:     form.AttributeName,
 | 
			
		||||
				AttributeSurname:  form.AttributeSurname,
 | 
			
		||||
				AttributeMail:     form.AttributeMail,
 | 
			
		||||
				Filter:            form.Filter,
 | 
			
		||||
				MsAdSAFormat:      form.MsAdSA,
 | 
			
		||||
				Enabled:           true,
 | 
			
		||||
				Name:              form.Name,
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
	case models.SMTP:
 | 
			
		||||
 
 | 
			
		||||
@@ -31,10 +31,6 @@
 | 
			
		||||
                                </div>
 | 
			
		||||
 | 
			
		||||
                                {{if eq $type 2}}
 | 
			
		||||
                                <div class="field">
 | 
			
		||||
                                    <label class="req" for="domain">{{.i18n.Tr "admin.auths.domain"}}</label>
 | 
			
		||||
                                    <input class="ipt ipt-large ipt-radius {{if .Err_Domain}}ipt-error{{end}}" id="domain" name="domain" value="{{.Source.LDAP.Name}}" required />
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <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 />
 | 
			
		||||
@@ -44,12 +40,24 @@
 | 
			
		||||
                                    <input class="ipt ipt-large ipt-radius {{if .Err_Port}}ipt-error{{end}}" id="port" name="port" value="{{.Source.LDAP.Port}}" required />
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div class="field">
 | 
			
		||||
                                    <label class="req" for="base_dn">{{.i18n.Tr "admin.auths.base_dn"}}</label>
 | 
			
		||||
                                    <input class="ipt ipt-large ipt-radius {{if .Err_BaseDN}}ipt-error{{end}}" id="base_dn" name="base_dn" value="{{.Source.LDAP.BaseDN}}" />
 | 
			
		||||
                                    <label for="use_ssl">{{.i18n.Tr "admin.auths.enable_tls"}}</label>
 | 
			
		||||
                                    <input name="use_ssl" type="checkbox" {{if .Source.LDAP.UseSSL}}checked{{end}}>
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div class="field">
 | 
			
		||||
                                    <label class="req" for="attribute_username">{{.i18n.Tr "admin.auths.attribute_username"}}</label>
 | 
			
		||||
                                    <input class="ipt ipt-large ipt-radius {{if .Err_Attributes}}ipt-error{{end}}" id="attribute_username" name="attribute_username" value="{{.Source.LDAP.AttributeUsername}}" />
 | 
			
		||||
                                    <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}}" />
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div class="field">
 | 
			
		||||
                                    <label 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" value="{{.Source.LDAP.BindPassword}}" />
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div class="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="{{.Source.LDAP.UserBase}}" />
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <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}}" />
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div class="field">
 | 
			
		||||
                                    <label for="attribute_name">{{.i18n.Tr "admin.auths.attribute_name"}}</label>
 | 
			
		||||
@@ -63,14 +71,6 @@
 | 
			
		||||
                                    <label class="req" for="attribute_mail">{{.i18n.Tr "admin.auths.attribute_mail"}}</label>
 | 
			
		||||
                                    <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 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}}" />
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div class="field">
 | 
			
		||||
                                    <label class="req" for="ms_ad_sa">{{.i18n.Tr "admin.auths.ms_ad_sa"}}</label>
 | 
			
		||||
                                    <input class="ipt ipt-large ipt-radius {{if .Err_MsAdSA}}ipt-error{{end}}" id="ms_ad_sa" name="ms_ad_sa" value="{{.Source.LDAP.MsAdSAFormat}}" />
 | 
			
		||||
                                </div>
 | 
			
		||||
 | 
			
		||||
                                {{else if eq $type 3}}
 | 
			
		||||
                                <div class="field">
 | 
			
		||||
 
 | 
			
		||||
@@ -27,10 +27,6 @@
 | 
			
		||||
                                    <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">
 | 
			
		||||
                                        <label class="req" for="domain">{{.i18n.Tr "admin.auths.domain"}}</label>
 | 
			
		||||
                                        <input class="ipt ipt-large ipt-radius {{if .Err_Domain}}ipt-error{{end}}" id="domain" name="domain" value="{{.domain}}" />
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                    <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="{{.host}}" />
 | 
			
		||||
@@ -40,12 +36,24 @@
 | 
			
		||||
                                        <input class="ipt ipt-large ipt-radius {{if .Err_Port}}ipt-error{{end}}" id="port" name="port" value="{{.port}}" />
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                    <div class="field">
 | 
			
		||||
                                        <label class="req" for="base_dn">{{.i18n.Tr "admin.auths.base_dn"}}</label>
 | 
			
		||||
                                        <input class="ipt ipt-large ipt-radius {{if .Err_BaseDN}}ipt-error{{end}}" id="base_dn" name="base_dn" value="{{.base_dn}}" />
 | 
			
		||||
                                        <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">
 | 
			
		||||
                                        <label class="req" for="attribute_username">{{.i18n.Tr "admin.auths.attribute_username"}}</label>
 | 
			
		||||
                                        <input class="ipt ipt-large ipt-radius {{if .Err_AttributeUsername}}ipt-error{{end}}" id="attribute_username" name="attribute_username" value="{{.attribute_username}}" />
 | 
			
		||||
                                        <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">
 | 
			
		||||
                                        <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" value="{{.bind_password}}" />
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                    <div class="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">
 | 
			
		||||
                                        <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">
 | 
			
		||||
                                        <label for="attribute_name">{{.i18n.Tr "admin.auths.attribute_name"}}</label>
 | 
			
		||||
@@ -59,14 +67,6 @@
 | 
			
		||||
                                        <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>
 | 
			
		||||
                                    <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="{{.filter}}" />
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                    <div class="field">
 | 
			
		||||
                                        <label class="req" for="ms_ad_sa">{{.i18n.Tr "admin.auths.ms_ad_sa"}}</label>
 | 
			
		||||
                                        <input class="ipt ipt-large ipt-radius {{if .Err_MsAdSA}}ipt-error{{end}}" id="ms_ad_sa" name="ms_ad_sa" value="{{.ms_ad_sa}}" />
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div class="smtp hidden">
 | 
			
		||||
                                    <div class="field">
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user