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:
		
					parent
					
						
							
								e2f95c2845
							
						
					
				
			
			
				commit
				
					
						834d92a47b
					
				
			
		
					 5 changed files with 37 additions and 6 deletions
				
			
		| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 -->
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue