mirror of
https://github.com/nicolabs/ldap-plugin.git
synced 2026-04-18 09:02:36 +02:00
[FIXES JENKINS-17281] Adding configuration options for the filters used to search for groups.
- It is somewhat confusing that there are two `group search filters` so I have decided to rename one. - The new name for the `groupSearchFilter` that is controlled from `LDAPBindSecurityRealm.groovy` is the `groupMembershipFilter` as this filter is used to determine what groups a specific user is a member of - That leaves `groupSearchFilter` as a nice clean name for the filter to search for named groups. - This should still respect any existing configuration, i.e. leaving these fields blank will leave the existing defaults or existing overrides in place... but it will make life easier for users going forward - Took quite some digging to figure out exactly what these filters were for... hopefully I have left things in a more obvious framing for anyone else following - I would like a better way to apply the `groupMembershipFilter` override, but this was the cleanest way I could maintain backwards compatibility
This commit is contained in:
parent
2faeb21b7a
commit
72a91027ab
|
|
@ -262,6 +262,23 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
|
|||
*/
|
||||
public final String groupSearchBase;
|
||||
|
||||
/**
|
||||
* Query to locate an entry that identifies the group, given the group name string. If non-null it will override
|
||||
* the default specified by {@link #GROUP_SEARCH}
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public final String groupSearchFilter;
|
||||
|
||||
/**
|
||||
* Query to locate the group entries that a user belongs to, given the user object. <code>{0}</code>
|
||||
* is the user's full DN while {1} is the username. If non-null it will override the default specified in
|
||||
* {@code LDAPBindSecurityRealm.groovy}
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public final String groupMembershipFilter;
|
||||
|
||||
/*
|
||||
Other configurations that are needed:
|
||||
|
||||
|
|
@ -314,19 +331,35 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
|
|||
*/
|
||||
private transient Map<String,CacheEntry<Set<String>>> groupDetailsCache = null;
|
||||
|
||||
/**
|
||||
* @deprecated retained for backwards binary compatibility.
|
||||
*/
|
||||
@Deprecated
|
||||
public LDAPSecurityRealm(String server, String rootDN, String userSearchBase, String userSearch, String groupSearchBase, String managerDN, String managerPassword, boolean inhibitInferRootDN) {
|
||||
this(server, rootDN, userSearchBase, userSearch, groupSearchBase, managerDN, managerPassword, inhibitInferRootDN, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated retained for backwards binary compatibility.
|
||||
*/
|
||||
@Deprecated
|
||||
public LDAPSecurityRealm(String server, String rootDN, String userSearchBase, String userSearch, String groupSearchBase, String managerDN, String managerPassword, boolean inhibitInferRootDN,
|
||||
boolean disableMailAddressResolver) {
|
||||
this(server, rootDN, userSearchBase, userSearch, groupSearchBase, managerDN, managerPassword, inhibitInferRootDN,
|
||||
disableMailAddressResolver, null);
|
||||
}
|
||||
|
||||
@DataBoundConstructor
|
||||
/**
|
||||
* @deprecated retained for backwards binary compatibility.
|
||||
*/
|
||||
@Deprecated
|
||||
public LDAPSecurityRealm(String server, String rootDN, String userSearchBase, String userSearch, String groupSearchBase, String managerDN, String managerPassword, boolean inhibitInferRootDN,
|
||||
boolean disableMailAddressResolver, CacheConfiguration cache) {
|
||||
this(server, rootDN, userSearchBase, userSearch, groupSearchBase, null, null, managerDN, managerPassword, inhibitInferRootDN, disableMailAddressResolver, cache);
|
||||
}
|
||||
|
||||
@DataBoundConstructor
|
||||
public LDAPSecurityRealm(String server, String rootDN, String userSearchBase, String userSearch, String groupSearchBase, String groupSearchFilter, String groupMembershipFilter, String managerDN, String managerPassword, boolean inhibitInferRootDN, boolean disableMailAddressResolver, CacheConfiguration cache) {
|
||||
this.server = server.trim();
|
||||
this.managerDN = fixEmpty(managerDN);
|
||||
this.managerPassword = Scrambler.scramble(fixEmpty(managerPassword));
|
||||
|
|
@ -337,6 +370,8 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
|
|||
userSearch = fixEmptyAndTrim(userSearch);
|
||||
this.userSearch = userSearch!=null ? userSearch : "uid={0}";
|
||||
this.groupSearchBase = fixEmptyAndTrim(groupSearchBase);
|
||||
this.groupSearchFilter = fixEmptyAndTrim(groupSearchFilter);
|
||||
this.groupMembershipFilter = fixEmptyAndTrim(groupMembershipFilter);
|
||||
this.disableMailAddressResolver = disableMailAddressResolver;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
|
@ -357,6 +392,14 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
|
|||
return cache == null ? null : cache.getTtl();
|
||||
}
|
||||
|
||||
public String getGroupMembershipFilter() {
|
||||
return groupMembershipFilter;
|
||||
}
|
||||
|
||||
public String getGroupSearchFilter() {
|
||||
return groupSearchFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Infer the root DN.
|
||||
*
|
||||
|
|
@ -416,6 +459,11 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
|
|||
|
||||
ldapTemplate = new LdapTemplate(findBean(InitialDirContextFactory.class, appContext));
|
||||
|
||||
if (groupMembershipFilter != null) {
|
||||
AuthoritiesPopulatorImpl authoritiesPopulator = findBean(AuthoritiesPopulatorImpl.class, appContext);
|
||||
authoritiesPopulator.setGroupSearchFilter(groupMembershipFilter);
|
||||
}
|
||||
|
||||
return new SecurityComponents(
|
||||
findBean(AuthenticationManager.class, appContext),
|
||||
new LDAPUserDetailsService(appContext));
|
||||
|
|
@ -457,10 +505,11 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
|
|||
|
||||
// TODO: obtain a DN instead so that we can obtain multiple attributes later
|
||||
String searchBase = groupSearchBase != null ? groupSearchBase : "";
|
||||
String searchFilter = groupSearchFilter != null ? groupSearchFilter : GROUP_SEARCH;
|
||||
final Set<String> groups = cachedGroups != null
|
||||
? cachedGroups
|
||||
: (Set<String>) ldapTemplate
|
||||
.searchForSingleAttributeValues(searchBase, GROUP_SEARCH, new String[]{groupname}, "cn");
|
||||
.searchForSingleAttributeValues(searchBase, searchFilter, new String[]{groupname}, "cn");
|
||||
if (cache != null && cachedGroups == null && !groups.isEmpty()) {
|
||||
synchronized (this) {
|
||||
if (groupDetailsCache == null) {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,12 @@ THE SOFTWARE.
|
|||
<f:entry title="${%Group search base}" help="/help/security/ldap/groupSearchBase.html">
|
||||
<f:textbox name="ldap.groupSearchBase" value="${instance.groupSearchBase}" />
|
||||
</f:entry>
|
||||
<f:entry title="${%Group search filter}" help="/plugin/ldap/help-groupSearchFilter.html">
|
||||
<f:textbox name="ldap.groupSearchFilter" value="${instance.groupSearchFilter}" />
|
||||
</f:entry>
|
||||
<f:entry title="${%Group membership filter}" help="/plugin/ldap/help-groupMembershipFilter.html">
|
||||
<f:textbox name="ldap.groupMembershipFilter" value="${instance.groupMembershipFilter}" />
|
||||
</f:entry>
|
||||
<f:entry title="${%Manager DN}" help="/help/security/ldap/managerDN.html">
|
||||
<f:textbox name="ldap.managerDN" value="${instance.managerDN}" autocomplete="off"
|
||||
checkUrl="'${rootURL}/securityRealms/LDAPSecurityRealm/serverCheck?field=managerDN&server='+encodeURIComponent(this.form.elements['ldap.server'].value)+'&managerDN='+encodeURIComponent(this.value)+'&managerPassword='+encodeURIComponent(this.form.elements['ldap.managerPassword'].value)"
|
||||
|
|
@ -56,7 +62,7 @@ THE SOFTWARE.
|
|||
<f:entry title="${%Disable Ldap Email Resolver}">
|
||||
<f:checkbox name="ldap.disableMailAddressResolver" checked="${instance.disableMailAddressResolver}"></f:checkbox>
|
||||
</f:entry>
|
||||
<f:optionalBlock name="ldap.cache" title="${%Enable cache}" checked="${instance.cache != null}">
|
||||
<f:optionalBlock name="ldap.cache" title="${%Enable cache}" checked="${instance.cache != null}" help="/plugin/ldap/help-cache.html">
|
||||
<f:entry title="${%Cache size}">
|
||||
<f:radio name="ldap.cache.size" value="10" checked="${instance.cacheSize == 10}" title="10"/>
|
||||
<st:nbsp />
|
||||
|
|
|
|||
30
src/main/webapp/help-groupMembershipFilter.html
Normal file
30
src/main/webapp/help-groupMembershipFilter.html
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<div>
|
||||
<p>
|
||||
When Jenkins resolves a user, the next step in the resolution process is to determine the LDAP groups that
|
||||
the user belongs to. This field controls the search filter that is used to determine group membership.
|
||||
If left blank, the default filter will be used.
|
||||
</p>
|
||||
<p>
|
||||
The default default filter is:
|
||||
</p>
|
||||
<pre>(| (member={0}) (uniqueMember={0}) (memberUid={1}))</pre>
|
||||
<p>
|
||||
This can be overridden by creating a file <code>$JENKINS_HOME/LDAPBindSecurityRealm.groovy</code>. Irrespective
|
||||
of what the default is, setting this filter to a non-blank value will determine the filter used.
|
||||
</p>
|
||||
<p>
|
||||
You are normally safe leaving this field unchanged, however for large LDAP servers where you are seeing messages
|
||||
such as <code>OperationNotSupportedException - Function Not Implemented</code>,
|
||||
<code>Administrative Limit Exceeded</code> or similar periodically when trying to login, then that would
|
||||
indicate that you should change to a more optimum filter for your LDAP server, namely one that queries only
|
||||
the required field, such as:
|
||||
</p>
|
||||
<pre>(member={0})</pre>
|
||||
<p>
|
||||
Note: in this field there are two available substitutions:
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>{0}</code> - the fully qualified DN of the user</li>
|
||||
<li><code>{1}</code> - the username portion of the user</li>
|
||||
</ul>
|
||||
</div>
|
||||
24
src/main/webapp/help-groupSearchFilter.html
Normal file
24
src/main/webapp/help-groupSearchFilter.html
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<div>
|
||||
<p>
|
||||
When Jenkins is asked to determine if a named group exists, it uses a default filter of:
|
||||
</p>
|
||||
<pre>(& (cn={0}) (| (objectclass=groupOfNames) (objectclass=groupOfUniqueNames) (objectclass=posixGroup)))</pre>
|
||||
<p>
|
||||
relative to the <code>Group search base</code> to determine if there is a group with the specified name (
|
||||
<code>{0}</code> is substituted by the name being searched for)
|
||||
</p>
|
||||
<p>
|
||||
If you know your LDAP server only stores group information in one specific object class, then you can improve
|
||||
group search performance by restricting the filter to just the required <code>objectclass</code>.
|
||||
</p>
|
||||
<p>
|
||||
Note: if you are using the LDAP security realm to connect to Active Directory (as opposed to using the
|
||||
<a href="https://wiki.jenkins-ci.org/display/JENKINS/Active+Directory+plugin">Active Directory plugin</a>'s
|
||||
security realm) then you will need to change this filter to:
|
||||
</p>
|
||||
<pre>(& (cn={0}) (objectclass=group) )</pre>
|
||||
<p>
|
||||
Note: if you leave this empty, the default search filter will be used, unless the
|
||||
<code>hudson.security.LDAPSecurityRealm.groupSearch</code> has been set to modify the default.
|
||||
</p>
|
||||
</div>
|
||||
Loading…
Reference in a new issue