mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Add check for LDAP group membership (#10869)
This is a port of gogs/gogs#4398 The only changes made by myself are: Add locales Add some JS to the UI Otherwise all code credit goes to @aboron Resolves #10829 Signed-off-by: jolheiser <john.olheiser@gmail.com> Co-authored-by: zeripath <art27@cantab.net>
This commit is contained in:
		@@ -30,6 +30,11 @@ type AuthenticationForm struct {
 | 
				
			|||||||
	SearchPageSize                int
 | 
						SearchPageSize                int
 | 
				
			||||||
	Filter                        string
 | 
						Filter                        string
 | 
				
			||||||
	AdminFilter                   string
 | 
						AdminFilter                   string
 | 
				
			||||||
 | 
						GroupsEnabled                 bool
 | 
				
			||||||
 | 
						GroupDN                       string
 | 
				
			||||||
 | 
						GroupFilter                   string
 | 
				
			||||||
 | 
						GroupMemberUID                string
 | 
				
			||||||
 | 
						UserUID                       string
 | 
				
			||||||
	RestrictedFilter              string
 | 
						RestrictedFilter              string
 | 
				
			||||||
	AllowDeactivateAll            bool
 | 
						AllowDeactivateAll            bool
 | 
				
			||||||
	IsActive                      bool
 | 
						IsActive                      bool
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,3 +103,21 @@ share the following fields:
 | 
				
			|||||||
      matching parameter will be substituted with the user's username.
 | 
					      matching parameter will be substituted with the user's username.
 | 
				
			||||||
    * Example: (&(objectClass=posixAccount)(cn=%s))
 | 
					    * Example: (&(objectClass=posixAccount)(cn=%s))
 | 
				
			||||||
    * Example: (&(objectClass=posixAccount)(uid=%s))
 | 
					    * Example: (&(objectClass=posixAccount)(uid=%s))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Verify group membership in LDAP** uses the following fields:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Group Search Base (optional)
 | 
				
			||||||
 | 
					    * The LDAP DN used for groups.
 | 
				
			||||||
 | 
					    * Example: ou=group,dc=mydomain,dc=com
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Group Name Filter (optional)
 | 
				
			||||||
 | 
					    * An LDAP filter declaring how to find valid groups in the above DN.
 | 
				
			||||||
 | 
					    * Example: (|(cn=gitea_users)(cn=admins))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* User Attribute in Group (optional)
 | 
				
			||||||
 | 
					    * Which user LDAP attribute is listed in the group.
 | 
				
			||||||
 | 
					    * Example: uid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Group Attribute for User (optional)
 | 
				
			||||||
 | 
					    * Which group LDAP attribute contains an array above user attribute names.
 | 
				
			||||||
 | 
					    * Example: memberUid
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
					// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Copyright 2020 The Gitea Authors. All rights reserved.
 | 
				
			||||||
// Use of this source code is governed by a MIT-style
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
// license that can be found in the LICENSE file.
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -13,7 +14,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ldap "gopkg.in/ldap.v3"
 | 
						"gopkg.in/ldap.v3"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SecurityProtocol protocol type
 | 
					// SecurityProtocol protocol type
 | 
				
			||||||
@@ -49,6 +50,11 @@ type Source struct {
 | 
				
			|||||||
	RestrictedFilter      string // Query filter to check if user is restricted
 | 
						RestrictedFilter      string // Query filter to check if user is restricted
 | 
				
			||||||
	Enabled               bool   // if this source is disabled
 | 
						Enabled               bool   // if this source is disabled
 | 
				
			||||||
	AllowDeactivateAll    bool   // Allow an empty search response to deactivate all users from this source
 | 
						AllowDeactivateAll    bool   // Allow an empty search response to deactivate all users from this source
 | 
				
			||||||
 | 
						GroupsEnabled         bool   // if the group checking is enabled
 | 
				
			||||||
 | 
						GroupDN               string // Group Search Base
 | 
				
			||||||
 | 
						GroupFilter           string // Group Name Filter
 | 
				
			||||||
 | 
						GroupMemberUID        string // Group Attribute containing array of UserUID
 | 
				
			||||||
 | 
						UserUID               string // User Attribute listed in Group
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SearchResult : user data
 | 
					// SearchResult : user data
 | 
				
			||||||
@@ -84,6 +90,28 @@ func (ls *Source) sanitizedUserDN(username string) (string, bool) {
 | 
				
			|||||||
	return fmt.Sprintf(ls.UserDN, username), true
 | 
						return fmt.Sprintf(ls.UserDN, username), true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ls *Source) sanitizedGroupFilter(group string) (string, bool) {
 | 
				
			||||||
 | 
						// See http://tools.ietf.org/search/rfc4515
 | 
				
			||||||
 | 
						badCharacters := "\x00*\\"
 | 
				
			||||||
 | 
						if strings.ContainsAny(group, badCharacters) {
 | 
				
			||||||
 | 
							log.Trace("Group filter invalid query characters: %s", group)
 | 
				
			||||||
 | 
							return "", false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return group, true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ls *Source) sanitizedGroupDN(groupDn string) (string, bool) {
 | 
				
			||||||
 | 
						// See http://tools.ietf.org/search/rfc4514: "special characters"
 | 
				
			||||||
 | 
						badCharacters := "\x00()*\\'\"#+;<>"
 | 
				
			||||||
 | 
						if strings.ContainsAny(groupDn, badCharacters) || strings.HasPrefix(groupDn, " ") || strings.HasSuffix(groupDn, " ") {
 | 
				
			||||||
 | 
							log.Trace("Group DN contains invalid query characters: %s", groupDn)
 | 
				
			||||||
 | 
							return "", false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return groupDn, true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
 | 
					func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
 | 
				
			||||||
	log.Trace("Search for LDAP user: %s", name)
 | 
						log.Trace("Search for LDAP user: %s", name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -279,11 +307,14 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
 | 
				
			|||||||
	var isAttributeSSHPublicKeySet = len(strings.TrimSpace(ls.AttributeSSHPublicKey)) > 0
 | 
						var isAttributeSSHPublicKeySet = len(strings.TrimSpace(ls.AttributeSSHPublicKey)) > 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	attribs := []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}
 | 
						attribs := []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}
 | 
				
			||||||
 | 
						if len(strings.TrimSpace(ls.UserUID)) > 0 {
 | 
				
			||||||
 | 
							attribs = append(attribs, ls.UserUID)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if isAttributeSSHPublicKeySet {
 | 
						if isAttributeSSHPublicKeySet {
 | 
				
			||||||
		attribs = append(attribs, ls.AttributeSSHPublicKey)
 | 
							attribs = append(attribs, ls.AttributeSSHPublicKey)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, userFilter, userDN)
 | 
						log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v', '%v' with filter '%s' and base '%s'", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, ls.UserUID, userFilter, userDN)
 | 
				
			||||||
	search := ldap.NewSearchRequest(
 | 
						search := ldap.NewSearchRequest(
 | 
				
			||||||
		userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
 | 
							userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
 | 
				
			||||||
		attribs, nil)
 | 
							attribs, nil)
 | 
				
			||||||
@@ -308,6 +339,51 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
 | 
				
			|||||||
	firstname := sr.Entries[0].GetAttributeValue(ls.AttributeName)
 | 
						firstname := sr.Entries[0].GetAttributeValue(ls.AttributeName)
 | 
				
			||||||
	surname := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
 | 
						surname := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
 | 
				
			||||||
	mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
 | 
						mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
 | 
				
			||||||
 | 
						uid := sr.Entries[0].GetAttributeValue(ls.UserUID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check group membership
 | 
				
			||||||
 | 
						if ls.GroupsEnabled {
 | 
				
			||||||
 | 
							groupFilter, ok := ls.sanitizedGroupFilter(ls.GroupFilter)
 | 
				
			||||||
 | 
							if !ok {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							groupDN, ok := ls.sanitizedGroupDN(ls.GroupDN)
 | 
				
			||||||
 | 
							if !ok {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log.Trace("Fetching groups '%v' with filter '%s' and base '%s'", ls.GroupMemberUID, groupFilter, groupDN)
 | 
				
			||||||
 | 
							groupSearch := ldap.NewSearchRequest(
 | 
				
			||||||
 | 
								groupDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, groupFilter,
 | 
				
			||||||
 | 
								[]string{ls.GroupMemberUID},
 | 
				
			||||||
 | 
								nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							srg, err := l.Search(groupSearch)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Error("LDAP group search failed: %v", err)
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							} else if len(srg.Entries) < 1 {
 | 
				
			||||||
 | 
								log.Error("LDAP group search failed: 0 entries")
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							isMember := false
 | 
				
			||||||
 | 
						Entries:
 | 
				
			||||||
 | 
							for _, group := range srg.Entries {
 | 
				
			||||||
 | 
								for _, member := range group.GetAttributeValues(ls.GroupMemberUID) {
 | 
				
			||||||
 | 
									if (ls.UserUID == "dn" && member == sr.Entries[0].DN) || member == uid {
 | 
				
			||||||
 | 
										isMember = true
 | 
				
			||||||
 | 
										break Entries
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if !isMember {
 | 
				
			||||||
 | 
								log.Error("LDAP group membership test failed")
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if isAttributeSSHPublicKeySet {
 | 
						if isAttributeSSHPublicKeySet {
 | 
				
			||||||
		sshPublicKey = sr.Entries[0].GetAttributeValues(ls.AttributeSSHPublicKey)
 | 
							sshPublicKey = sr.Entries[0].GetAttributeValues(ls.AttributeSSHPublicKey)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2098,6 +2098,11 @@ auths.filter = User Filter
 | 
				
			|||||||
auths.admin_filter = Admin Filter
 | 
					auths.admin_filter = Admin Filter
 | 
				
			||||||
auths.restricted_filter = Restricted Filter
 | 
					auths.restricted_filter = Restricted Filter
 | 
				
			||||||
auths.restricted_filter_helper = Leave empty to not set any users as restricted. Use an asterisk ('*') to set all users that do not match Admin Filter as restricted.
 | 
					auths.restricted_filter_helper = Leave empty to not set any users as restricted. Use an asterisk ('*') to set all users that do not match Admin Filter as restricted.
 | 
				
			||||||
 | 
					auths.verify_group_membership = Verify group membership in LDAP
 | 
				
			||||||
 | 
					auths.group_search_base = Group Search Base DN
 | 
				
			||||||
 | 
					auths.valid_groups_filter = Valid Groups Filter
 | 
				
			||||||
 | 
					auths.group_attribute_list_users = Group Attribute Containing List Of Users
 | 
				
			||||||
 | 
					auths.user_attribute_in_group = User Attribute Listed In Group
 | 
				
			||||||
auths.ms_ad_sa = MS AD Search Attributes
 | 
					auths.ms_ad_sa = MS AD Search Attributes
 | 
				
			||||||
auths.smtp_auth = SMTP Authentication Type
 | 
					auths.smtp_auth = SMTP Authentication Type
 | 
				
			||||||
auths.smtphost = SMTP Host
 | 
					auths.smtphost = SMTP Host
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,6 +129,11 @@ func parseLDAPConfig(form auth.AuthenticationForm) *models.LDAPConfig {
 | 
				
			|||||||
			AttributeSSHPublicKey: form.AttributeSSHPublicKey,
 | 
								AttributeSSHPublicKey: form.AttributeSSHPublicKey,
 | 
				
			||||||
			SearchPageSize:        pageSize,
 | 
								SearchPageSize:        pageSize,
 | 
				
			||||||
			Filter:                form.Filter,
 | 
								Filter:                form.Filter,
 | 
				
			||||||
 | 
								GroupsEnabled:         form.GroupsEnabled,
 | 
				
			||||||
 | 
								GroupDN:               form.GroupDN,
 | 
				
			||||||
 | 
								GroupFilter:           form.GroupFilter,
 | 
				
			||||||
 | 
								GroupMemberUID:        form.GroupMemberUID,
 | 
				
			||||||
 | 
								UserUID:               form.UserUID,
 | 
				
			||||||
			AdminFilter:           form.AdminFilter,
 | 
								AdminFilter:           form.AdminFilter,
 | 
				
			||||||
			RestrictedFilter:      form.RestrictedFilter,
 | 
								RestrictedFilter:      form.RestrictedFilter,
 | 
				
			||||||
			AllowDeactivateAll:    form.AllowDeactivateAll,
 | 
								AllowDeactivateAll:    form.AllowDeactivateAll,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -99,6 +99,31 @@
 | 
				
			|||||||
					    <label for="attribute_ssh_public_key">{{.i18n.Tr "admin.auths.attribute_ssh_public_key"}}</label>
 | 
										    <label for="attribute_ssh_public_key">{{.i18n.Tr "admin.auths.attribute_ssh_public_key"}}</label>
 | 
				
			||||||
					    <input id="attribute_ssh_public_key" name="attribute_ssh_public_key" value="{{$cfg.AttributeSSHPublicKey}}" placeholder="e.g. SshPublicKey">
 | 
										    <input id="attribute_ssh_public_key" name="attribute_ssh_public_key" value="{{$cfg.AttributeSSHPublicKey}}" placeholder="e.g. SshPublicKey">
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
 | 
										<div class="inline field">
 | 
				
			||||||
 | 
											<div class="ui checkbox">
 | 
				
			||||||
 | 
												<label for="groups_enabled"><strong>{{.i18n.Tr "admin.auths.verify_group_membership"}}</strong></label>
 | 
				
			||||||
 | 
												<input id="groups_enabled" name="groups_enabled" type="checkbox" {{if $cfg.GroupsEnabled}}checked{{end}}>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
										</div>
 | 
				
			||||||
 | 
										<div id="groups_enabled_change">
 | 
				
			||||||
 | 
											<div class="field">
 | 
				
			||||||
 | 
												<label for="group_dn">{{.i18n.Tr "admin.auths.group_search_base"}}</label>
 | 
				
			||||||
 | 
												<input id="group_dn" name="group_dn" value="{{$cfg.GroupDN}}" placeholder="e.g. ou=group,dc=mydomain,dc=com">
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
											<div class="field">
 | 
				
			||||||
 | 
												<label for="group_filter">{{.i18n.Tr "admin.auths.valid_groups_filter"}}</label>
 | 
				
			||||||
 | 
												<input id="group_filter" name="group_filter" value="{{$cfg.GroupFilter}}" placeholder="e.g. (|(cn=gitea_users)(cn=admins))">
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
											<div class="field">
 | 
				
			||||||
 | 
												<label for="group_member_uid">{{.i18n.Tr "admin.auths.group_attribute_list_users"}}</label>
 | 
				
			||||||
 | 
												<input id="group_member_uid" name="group_member_uid" value="{{$cfg.GroupMemberUID}}" placeholder="e.g. memberUid">
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
											<div class="field">
 | 
				
			||||||
 | 
												<label for="user_uid">{{.i18n.Tr "admin.auths.user_attribute_in_group"}}</label>
 | 
				
			||||||
 | 
												<input id="user_uid" name="user_uid" value="{{$cfg.UserUID}}" placeholder="e.g. uid">
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
											<br/>
 | 
				
			||||||
 | 
										</div>
 | 
				
			||||||
					{{if .Source.IsLDAP}}
 | 
										{{if .Source.IsLDAP}}
 | 
				
			||||||
						<div class="inline field">
 | 
											<div class="inline field">
 | 
				
			||||||
							<div class="ui checkbox">
 | 
												<div class="ui checkbox">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,6 +71,31 @@
 | 
				
			|||||||
	    <label for="attribute_ssh_public_key">{{.i18n.Tr "admin.auths.attribute_ssh_public_key"}}</label>
 | 
						    <label for="attribute_ssh_public_key">{{.i18n.Tr "admin.auths.attribute_ssh_public_key"}}</label>
 | 
				
			||||||
	    <input id="attribute_ssh_public_key" name="attribute_ssh_public_key" value="{{.attribute_ssh_public_key}}" placeholder="e.g. SshPublicKey">
 | 
						    <input id="attribute_ssh_public_key" name="attribute_ssh_public_key" value="{{.attribute_ssh_public_key}}" placeholder="e.g. SshPublicKey">
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
 | 
						<div class="inline field">
 | 
				
			||||||
 | 
							<div class="ui checkbox">
 | 
				
			||||||
 | 
								<label for="groups_enabled"><strong>{{.i18n.Tr "admin.auths.verify_group_membership"}}</strong></label>
 | 
				
			||||||
 | 
								<input id="groups_enabled" name="groups_enabled" type="checkbox" {{if .groups_enabled}}checked{{end}}>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
						<div id="groups_enabled_change">
 | 
				
			||||||
 | 
							<div class="field">
 | 
				
			||||||
 | 
								<label for="group_dn">{{.i18n.Tr "admin.auths.group_search_base"}}</label>
 | 
				
			||||||
 | 
								<input id="group_dn" name="group_dn" value="{{.group_dn}}" placeholder="e.g. ou=group,dc=mydomain,dc=com">
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div class="field">
 | 
				
			||||||
 | 
								<label for="group_filter">{{.i18n.Tr "admin.auths.valid_groups_filter"}}</label>
 | 
				
			||||||
 | 
								<input id="group_filter" name="group_filter" value="{{.group_filter}}" placeholder="e.g. (|(cn=gitea_users)(cn=admins))">
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div class="field">
 | 
				
			||||||
 | 
								<label for="group_member_uid">{{.i18n.Tr "admin.auths.group_attribute_list_users"}}</label>
 | 
				
			||||||
 | 
								<input id="group_member_uid" name="group_member_uid" value="{{.group_member_uid}}" placeholder="e.g. memberUid">
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div class="field">
 | 
				
			||||||
 | 
								<label for="user_uid">{{.i18n.Tr "admin.auths.user_attribute_in_group"}}</label>
 | 
				
			||||||
 | 
								<input id="user_uid" name="user_uid" value="{{.user_uid}}" placeholder="e.g. uid">
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<br/>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
	<div class="ldap inline field {{if not (eq .type 2)}}hide{{end}}">
 | 
						<div class="ldap inline field {{if not (eq .type 2)}}hide{{end}}">
 | 
				
			||||||
		<div class="ui checkbox">
 | 
							<div class="ui checkbox">
 | 
				
			||||||
			<label for="use_paged_search"><strong>{{.i18n.Tr "admin.auths.use_paged_search"}}</strong></label>
 | 
								<label for="use_paged_search"><strong>{{.i18n.Tr "admin.auths.use_paged_search"}}</strong></label>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1795,6 +1795,14 @@ function initAdmin() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function onVerifyGroupMembershipChange() {
 | 
				
			||||||
 | 
					    if ($('#groups_enabled').is(':checked')) {
 | 
				
			||||||
 | 
					      $('#groups_enabled_change').show();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      $('#groups_enabled_change').hide();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // New authentication
 | 
					  // New authentication
 | 
				
			||||||
  if ($('.admin.new.authentication').length > 0) {
 | 
					  if ($('.admin.new.authentication').length > 0) {
 | 
				
			||||||
    $('#auth_type').on('change', function () {
 | 
					    $('#auth_type').on('change', function () {
 | 
				
			||||||
@@ -1835,6 +1843,7 @@ function initAdmin() {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      if (authType === '2' || authType === '5') {
 | 
					      if (authType === '2' || authType === '5') {
 | 
				
			||||||
        onSecurityProtocolChange();
 | 
					        onSecurityProtocolChange();
 | 
				
			||||||
 | 
					        onVerifyGroupMembershipChange();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (authType === '2') {
 | 
					      if (authType === '2') {
 | 
				
			||||||
        onUsePagedSearchChange();
 | 
					        onUsePagedSearchChange();
 | 
				
			||||||
@@ -1845,12 +1854,15 @@ function initAdmin() {
 | 
				
			|||||||
    $('#use_paged_search').on('change', onUsePagedSearchChange);
 | 
					    $('#use_paged_search').on('change', onUsePagedSearchChange);
 | 
				
			||||||
    $('#oauth2_provider').on('change', onOAuth2Change);
 | 
					    $('#oauth2_provider').on('change', onOAuth2Change);
 | 
				
			||||||
    $('#oauth2_use_custom_url').on('change', onOAuth2UseCustomURLChange);
 | 
					    $('#oauth2_use_custom_url').on('change', onOAuth2UseCustomURLChange);
 | 
				
			||||||
 | 
					    $('#groups_enabled').on('change', onVerifyGroupMembershipChange);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  // Edit authentication
 | 
					  // Edit authentication
 | 
				
			||||||
  if ($('.admin.edit.authentication').length > 0) {
 | 
					  if ($('.admin.edit.authentication').length > 0) {
 | 
				
			||||||
    const authType = $('#auth_type').val();
 | 
					    const authType = $('#auth_type').val();
 | 
				
			||||||
    if (authType === '2' || authType === '5') {
 | 
					    if (authType === '2' || authType === '5') {
 | 
				
			||||||
      $('#security_protocol').on('change', onSecurityProtocolChange);
 | 
					      $('#security_protocol').on('change', onSecurityProtocolChange);
 | 
				
			||||||
 | 
					      $('#groups_enabled').on('change', onVerifyGroupMembershipChange);
 | 
				
			||||||
 | 
					      onVerifyGroupMembershipChange();
 | 
				
			||||||
      if (authType === '2') {
 | 
					      if (authType === '2') {
 | 
				
			||||||
        $('#use_paged_search').on('change', onUsePagedSearchChange);
 | 
					        $('#use_paged_search').on('change', onUsePagedSearchChange);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user