LDAP: Fetch attributes in Bind DN context option

This is feature is workaround for #2628 (JumpCloud) and some other services
that allow LDAP search only under BindDN user account, but not allow any LDAP
search query in logged user DN context.

Such approach is an alternative to minimal permissions security pattern for
BindDN user.
This commit is contained in:
Adam Strzelecki 2016-02-16 12:33:16 +01:00
parent e2f95c2845
commit 834d92a47b
5 changed files with 37 additions and 6 deletions

View file

@ -921,6 +921,7 @@ auths.attribute_username_placeholder = Leave empty to use sign-in form field val
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 = Email attribute auths.attribute_mail = Email attribute
auths.attributes_in_bind = Fetch attributes in Bind DN context
auths.filter = User Filter auths.filter = User Filter
auths.admin_filter = Admin Filter auths.admin_filter = Admin Filter
auths.ms_ad_sa = Ms Ad SA auths.ms_ad_sa = Ms Ad SA

View file

@ -23,6 +23,7 @@ type AuthenticationForm struct {
AttributeName string AttributeName string
AttributeSurname string AttributeSurname string
AttributeMail string AttributeMail string
AttributesInBind bool
Filter string Filter string
AdminFilter string AdminFilter string
IsActive bool IsActive bool

View file

@ -31,6 +31,7 @@ type Source struct {
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
AttributesInBind bool // fetch attributes in bind context (not user)
Filter string // Query filter to validate entry Filter string // Query filter to validate entry
AdminFilter string // Query filter to check if user is admin AdminFilter string // Query filter to check if user is admin
Enabled bool // if this source is disabled Enabled bool // if this source is disabled
@ -130,14 +131,14 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
} }
} }
log.Trace("Binding with userDN: %s", userDN) if directBind || !ls.AttributesInBind {
err = l.Bind(userDN, passwd) // binds user (checking password) before looking-up attributes in user context
err = bindUser(l, userDN, passwd)
if err != nil { if err != nil {
log.Debug("LDAP auth. failed for %s, reason: %v", userDN, err)
return "", "", "", "", false, false return "", "", "", "", false, false
} }
}
log.Trace("Bound successfully with userDN: %s", userDN)
userFilter, ok := ls.sanitizedUserQuery(name) userFilter, ok := ls.sanitizedUserQuery(name)
if !ok { if !ok {
return "", "", "", "", false, false return "", "", "", "", false, false
@ -184,9 +185,28 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
} }
} }
if !directBind && ls.AttributesInBind {
// binds user (checking password) after looking-up attributes in BindDN context
err = bindUser(l, userDN, passwd)
if err != nil {
return "", "", "", "", false, false
}
}
return username_attr, name_attr, sn_attr, mail_attr, admin_attr, true return username_attr, name_attr, sn_attr, mail_attr, admin_attr, true
} }
func bindUser(l *ldap.Conn, userDN, passwd string) error {
log.Trace("Binding with userDN: %s", userDN)
err := l.Bind(userDN, passwd)
if err != nil {
log.Debug("LDAP auth. failed for %s, reason: %v", userDN, err)
return err
}
log.Trace("Bound successfully with userDN: %s", userDN)
return err
}
func ldapDial(ls *Source) (*ldap.Conn, error) { func ldapDial(ls *Source) (*ldap.Conn, error) {
if ls.UseSSL { if ls.UseSSL {
log.Debug("Using TLS for LDAP without verifying: %v", ls.SkipVerify) log.Debug("Using TLS for LDAP without verifying: %v", ls.SkipVerify)

View file

@ -81,6 +81,7 @@ func parseLDAPConfig(form auth.AuthenticationForm) *models.LDAPConfig {
AttributeName: form.AttributeName, AttributeName: form.AttributeName,
AttributeSurname: form.AttributeSurname, AttributeSurname: form.AttributeSurname,
AttributeMail: form.AttributeMail, AttributeMail: form.AttributeMail,
AttributesInBind: form.AttributesInBind,
Filter: form.Filter, Filter: form.Filter,
AdminFilter: form.AdminFilter, AdminFilter: form.AdminFilter,
Enabled: true, Enabled: true,

View file

@ -79,6 +79,14 @@
<label for="attribute_mail">{{.i18n.Tr "admin.auths.attribute_mail"}}</label> <label for="attribute_mail">{{.i18n.Tr "admin.auths.attribute_mail"}}</label>
<input id="attribute_mail" name="attribute_mail" value="{{$cfg.AttributeMail}}" placeholder="e.g. mail" required> <input id="attribute_mail" name="attribute_mail" value="{{$cfg.AttributeMail}}" placeholder="e.g. mail" required>
</div> </div>
{{if .Source.IsLDAP}}
<div class="inline field">
<div class="ui checkbox">
<label><strong>{{.i18n.Tr "admin.auths.attributes_in_bind"}}</strong></label>
<input name="attributes_in_bind" type="checkbox" {{if $cfg.AttributesInBind}}checked{{end}}>
</div>
</div>
{{end}}
{{end}} {{end}}
<!-- SMTP --> <!-- SMTP -->