Allow configuring case sensitivity (usually you want to leave it as case insensitive as most LDAP attributes are case insensitive, but when using custom attributes you may need to configure a case sensitive strategy)

- Bumps core to 1.566 to pick up IdStrategy support
This commit is contained in:
Stephen Connolly 2014-08-12 10:51:41 +01:00
parent 98db72371c
commit 2104712d8c
5 changed files with 121 additions and 13 deletions

20
pom.xml
View file

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.jenkins-ci.plugins</groupId> <groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId> <artifactId>plugin</artifactId>
<version>1.480</version> <version>1.566</version>
</parent> </parent>
<artifactId>ldap</artifactId> <artifactId>ldap</artifactId>
@ -37,16 +37,6 @@
<id>repo.jenkins-ci.org</id> <id>repo.jenkins-ci.org</id>
<url>http://repo.jenkins-ci.org/public/</url> <url>http://repo.jenkins-ci.org/public/</url>
</repository> </repository>
<repository><!-- only until we release ant and javadoc plugins -->
<id>maven.jenkins-ci.org</id>
<url>http://maven.jenkins-ci.org/content/repositories/snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories> </repositories>
<pluginRepositories> <pluginRepositories>
<pluginRepository> <pluginRepository>
@ -55,6 +45,14 @@
</pluginRepository> </pluginRepository>
</pluginRepositories> </pluginRepositories>
<dependencies>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>mailer</artifactId>
<version>1.8</version>
</dependency>
</dependencies>
<build> <build>
<pluginManagement> <pluginManagement>
<plugins> <plugins>

View file

@ -30,6 +30,8 @@ import hudson.Extension;
import static hudson.Util.fixEmpty; import static hudson.Util.fixEmpty;
import static hudson.Util.fixEmptyAndTrim; import static hudson.Util.fixEmptyAndTrim;
import static hudson.Util.fixNull; import static hudson.Util.fixNull;
import hudson.Util;
import hudson.model.AbstractDescribableImpl; import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor; import hudson.model.Descriptor;
import hudson.model.User; import hudson.model.User;
@ -68,6 +70,8 @@ import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes; import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext; import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext; import javax.naming.directory.InitialDirContext;
import jenkins.model.IdStrategy;
import jenkins.model.Jenkins; import jenkins.model.Jenkins;
import jenkins.security.plugins.ldap.FromGroupSearchLDAPGroupMembershipStrategy; import jenkins.security.plugins.ldap.FromGroupSearchLDAPGroupMembershipStrategy;
import jenkins.security.plugins.ldap.LDAPGroupMembershipStrategy; import jenkins.security.plugins.ldap.LDAPGroupMembershipStrategy;
@ -361,6 +365,10 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
private final String mailAddressAttributeName; private final String mailAddressAttributeName;
private final IdStrategy userIdStrategy;
private final IdStrategy groupIdStrategy;
/** /**
* @deprecated retained for backwards binary compatibility. * @deprecated retained for backwards binary compatibility.
*/ */
@ -420,8 +428,16 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
this(server, rootDN, userSearchBase, userSearch, groupSearchBase, groupSearchFilter, new FromGroupSearchLDAPGroupMembershipStrategy(groupMembershipFilter), managerDN, managerPasswordSecret, inhibitInferRootDN, disableMailAddressResolver, cache, environmentProperties, displayNameAttributeName, mailAddressAttributeName); this(server, rootDN, userSearchBase, userSearch, groupSearchBase, groupSearchFilter, new FromGroupSearchLDAPGroupMembershipStrategy(groupMembershipFilter), managerDN, managerPasswordSecret, inhibitInferRootDN, disableMailAddressResolver, cache, environmentProperties, displayNameAttributeName, mailAddressAttributeName);
} }
@DataBoundConstructor /**
* @deprecated retained for backwards binary compatibility.
*/
@Deprecated
public LDAPSecurityRealm(String server, String rootDN, String userSearchBase, String userSearch, String groupSearchBase, String groupSearchFilter, LDAPGroupMembershipStrategy groupMembershipStrategy, String managerDN, Secret managerPasswordSecret, boolean inhibitInferRootDN, boolean disableMailAddressResolver, CacheConfiguration cache, EnvironmentProperty[] environmentProperties, String displayNameAttributeName, String mailAddressAttributeName) { public LDAPSecurityRealm(String server, String rootDN, String userSearchBase, String userSearch, String groupSearchBase, String groupSearchFilter, LDAPGroupMembershipStrategy groupMembershipStrategy, String managerDN, Secret managerPasswordSecret, boolean inhibitInferRootDN, boolean disableMailAddressResolver, CacheConfiguration cache, EnvironmentProperty[] environmentProperties, String displayNameAttributeName, String mailAddressAttributeName) {
this(server, rootDN, userSearchBase, userSearch, groupSearchBase, groupSearchFilter, groupMembershipStrategy, managerDN, managerPasswordSecret, inhibitInferRootDN, disableMailAddressResolver, cache, environmentProperties, displayNameAttributeName, mailAddressAttributeName, IdStrategy.CASE_INSENSITIVE, IdStrategy.CASE_INSENSITIVE);
}
@DataBoundConstructor
public LDAPSecurityRealm(String server, String rootDN, String userSearchBase, String userSearch, String groupSearchBase, String groupSearchFilter, LDAPGroupMembershipStrategy groupMembershipStrategy, String managerDN, Secret managerPasswordSecret, boolean inhibitInferRootDN, boolean disableMailAddressResolver, CacheConfiguration cache, EnvironmentProperty[] environmentProperties, String displayNameAttributeName, String mailAddressAttributeName, IdStrategy userIdStrategy, IdStrategy groupIdStrategy) {
this.server = server.trim(); this.server = server.trim();
this.managerDN = fixEmpty(managerDN); this.managerDN = fixEmpty(managerDN);
this.managerPasswordSecret = managerPasswordSecret; this.managerPasswordSecret = managerPasswordSecret;
@ -443,6 +459,8 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
DescriptorImpl.DEFAULT_DISPLAYNAME_ATTRIBUTE_NAME); DescriptorImpl.DEFAULT_DISPLAYNAME_ATTRIBUTE_NAME);
this.mailAddressAttributeName = StringUtils.defaultString(fixEmptyAndTrim(mailAddressAttributeName), this.mailAddressAttributeName = StringUtils.defaultString(fixEmptyAndTrim(mailAddressAttributeName),
DescriptorImpl.DEFAULT_MAILADDRESS_ATTRIBUTE_NAME); DescriptorImpl.DEFAULT_MAILADDRESS_ATTRIBUTE_NAME);
this.userIdStrategy = userIdStrategy == null ? IdStrategy.CASE_INSENSITIVE : userIdStrategy;
this.groupIdStrategy = groupIdStrategy == null ? IdStrategy.CASE_INSENSITIVE : groupIdStrategy;
} }
private Object readResolve() { private Object readResolve() {
@ -460,7 +478,7 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
public String getServerUrl() { public String getServerUrl() {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
boolean first = true; boolean first = true;
for (String s: server.split("\\s+")) { for (String s: Util.fixNull(server).split("\\s+")) {
if (s.trim().length() == 0) continue; if (s.trim().length() == 0) continue;
if (first) first = false; else buf.append(' '); if (first) first = false; else buf.append(' ');
buf.append(addPrefix(s)); buf.append(addPrefix(s));
@ -468,6 +486,16 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
return buf.toString(); return buf.toString();
} }
@Override
public IdStrategy getUserIdStrategy() {
return userIdStrategy == null ? IdStrategy.CASE_INSENSITIVE : userIdStrategy;
}
@Override
public IdStrategy getGroupIdStrategy() {
return groupIdStrategy == null ? IdStrategy.CASE_INSENSITIVE : groupIdStrategy;
}
public CacheConfiguration getCache() { public CacheConfiguration getCache() {
return cache; return cache;
} }
@ -941,6 +969,10 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
return Messages.LDAPSecurityRealm_DisplayName(); return Messages.LDAPSecurityRealm_DisplayName();
} }
public IdStrategy getDefaultIdStrategy() {
return IdStrategy.CASE_INSENSITIVE;
}
// note that this works better in 1.528+ (JENKINS-19124) // note that this works better in 1.528+ (JENKINS-19124)
public FormValidation doCheckServer(@QueryParameter String value, @QueryParameter String managerDN, @QueryParameter Secret managerPasswordSecret) { public FormValidation doCheckServer(@QueryParameter String value, @QueryParameter String managerDN, @QueryParameter Secret managerPasswordSecret) {
String server = value; String server = value;

View file

@ -40,6 +40,10 @@ THE SOFTWARE.
<f:entry field="userSearch" title="${%User search filter}"> <f:entry field="userSearch" title="${%User search filter}">
<f:textbox default="${descriptor.DEFAULT_USER_SEARCH}"/> <f:textbox default="${descriptor.DEFAULT_USER_SEARCH}"/>
</f:entry> </f:entry>
<f:advanced title="${%Case sensitivity}">
<f:dropdownDescriptorSelector field="userIdStrategy" title="${%Login name case sensitivity}" default="${descriptor.defaultIdStrategy}"/>
<f:dropdownDescriptorSelector field="groupIdStrategy" title="${%Group name case sensitivity}" default="${descriptor.defaultIdStrategy}"/>
</f:advanced>
<f:entry field="groupSearchBase" title="${%Group search base}"> <f:entry field="groupSearchBase" title="${%Group search base}">
<f:textbox/> <f:textbox/>
</f:entry> </f:entry>

View file

@ -0,0 +1,18 @@
<div>
Almost all LDAP schemas use an attribute (<code>cn</code>) for the group name that is specified to be case
insensitive. Unless you are connecting to a LDAP server that uses a different search attribute than the defaults
you should leave this as <code>Case insensitive</code>.
<p>
<b>Recommendations:</b>
</p>
<ul>
<li>
If your group search filter is blank or contains <code>cn={0}</code> then select
<code>Case insensitive</code>.
</li>
<li>
Otherwise consult the LDAP schema of your LDAP server to determine the correct selection, with
<code>Case insensitive</code> being the best choice for the lazy.
</li>
</ul>
</div>

View file

@ -0,0 +1,56 @@
<div>
Almost all LDAP schemas use an attribute (<code>uid</code> or <code>mail</code>) for the user name that is
specified to be case insensitive. Unless you are connecting to a LDAP server that uses a different search attribute
than the defaults you should leave this as <code>Case insensitive</code>.
<p>
<b>Recommendations:</b>
</p>
<ul>
<li>If your user search filter is <code>uid={0}</code> then select <code>Case insensitive</code>.</li>
<li>If your user search filter is <code>mail={0}</code> then select <code>Case insensitive</code>.</li>
<li>
Otherwise consult the LDAP schema of your LDAP server to determine the correct selection, with
<code>Case insensitive</code> being the best choice for the lazy.
</li>
</ul>
<p>
<b>Note:</b>
<blockquote>If you are using an email address attribute for the user search you will want to ask the
mail server administrator whether they have case sensitive mailboxes.
<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821 Section 2.4</a> specifies:
<blockquote>
The local-part of a mailbox MUST BE treated as case sensitive. Therefore, SMTP implementations MUST take care
to preserve the case of mailbox local-parts. Mailbox domains are not case sensitive.
</blockquote>
This is in conflict with the case sensitivity rules for the standard LDAP attribute used to hold email addresses
(<code>mail</code>) which specifies <code>caseIgnoreIA5Match</code>, e.g. as noted in
<a href="http://www.ietf.org/rfc/rfc2798.txt">RFC 2798</a>
<blockquote>
<pre>( 0.9.2342.19200300.100.1.3
NAME 'mail'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
</pre>
Note: <a href="http://www.ietf.org/rfc/rfc1274.txt">RFC 1274</a> uses the longer name
'<code>rfc822Mailbox</code>' and syntax OID of <code>0.9.2342.19200300.100.3.5</code>. All recent LDAP documents
and most
deployed LDAP implementations refer to this attribute as '<code>mail</code>'
and define the IA5 String syntax using using the OID
<code>1.3.6.1.4.1.1466.115.121.1.26</code>, as is done here.
</blockquote>
So when the user search filter is <code>mail={0}</code> it is pointless to select anything other than
<code>Case insensitive</code> as the LDAP server will be ignoring case when searching anyway.
<br/>
If you do need to select a case sensitive strategy because you are searching on a custom attribute you should note
that the <code>Case sensitive (email address)</code>
strategy applies <a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>'s rules on case sensitivity (i.e. the
local-part is case sensitive and the mailbox domain is case insensitive), thus with that strategy
<code>JOE@ACME.COM</code> and <code>JOE@acme.com</code> will be considered the same Jenkins user
while <code>joe@acme.com</code> will be considered as a different Jenkins user.
</blockquote>
</p>
<p>
<b>Note:</b> UNIX login names are case sensitive
</p>
</div>