From 2104712d8c2bbce060a218f7a997ada49ebced28 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Tue, 12 Aug 2014 10:51:41 +0100 Subject: [PATCH] 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 --- pom.xml | 20 +++---- .../hudson/security/LDAPSecurityRealm.java | 36 +++++++++++- .../security/LDAPSecurityRealm/config.jelly | 4 ++ .../help-groupIdStrategy.html | 18 ++++++ .../help-userIdStrategy.html | 56 +++++++++++++++++++ 5 files changed, 121 insertions(+), 13 deletions(-) create mode 100644 src/main/resources/hudson/security/LDAPSecurityRealm/help-groupIdStrategy.html create mode 100644 src/main/resources/hudson/security/LDAPSecurityRealm/help-userIdStrategy.html diff --git a/pom.xml b/pom.xml index 2d92f36..3bc21d6 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 1.480 + 1.566 ldap @@ -37,16 +37,6 @@ repo.jenkins-ci.org http://repo.jenkins-ci.org/public/ - - maven.jenkins-ci.org - http://maven.jenkins-ci.org/content/repositories/snapshots/ - - false - - - true - - @@ -55,6 +45,14 @@ + + + org.jenkins-ci.plugins + mailer + 1.8 + + + diff --git a/src/main/java/hudson/security/LDAPSecurityRealm.java b/src/main/java/hudson/security/LDAPSecurityRealm.java index f702232..8d5bfa5 100644 --- a/src/main/java/hudson/security/LDAPSecurityRealm.java +++ b/src/main/java/hudson/security/LDAPSecurityRealm.java @@ -30,6 +30,8 @@ import hudson.Extension; import static hudson.Util.fixEmpty; import static hudson.Util.fixEmptyAndTrim; import static hudson.Util.fixNull; + +import hudson.Util; import hudson.model.AbstractDescribableImpl; import hudson.model.Descriptor; import hudson.model.User; @@ -68,6 +70,8 @@ import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; + +import jenkins.model.IdStrategy; import jenkins.model.Jenkins; import jenkins.security.plugins.ldap.FromGroupSearchLDAPGroupMembershipStrategy; import jenkins.security.plugins.ldap.LDAPGroupMembershipStrategy; @@ -361,6 +365,10 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { private final String mailAddressAttributeName; + private final IdStrategy userIdStrategy; + + private final IdStrategy groupIdStrategy; + /** * @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); } - @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) { + 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.managerDN = fixEmpty(managerDN); this.managerPasswordSecret = managerPasswordSecret; @@ -443,6 +459,8 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { DescriptorImpl.DEFAULT_DISPLAYNAME_ATTRIBUTE_NAME); this.mailAddressAttributeName = StringUtils.defaultString(fixEmptyAndTrim(mailAddressAttributeName), DescriptorImpl.DEFAULT_MAILADDRESS_ATTRIBUTE_NAME); + this.userIdStrategy = userIdStrategy == null ? IdStrategy.CASE_INSENSITIVE : userIdStrategy; + this.groupIdStrategy = groupIdStrategy == null ? IdStrategy.CASE_INSENSITIVE : groupIdStrategy; } private Object readResolve() { @@ -460,7 +478,7 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { public String getServerUrl() { StringBuilder buf = new StringBuilder(); boolean first = true; - for (String s: server.split("\\s+")) { + for (String s: Util.fixNull(server).split("\\s+")) { if (s.trim().length() == 0) continue; if (first) first = false; else buf.append(' '); buf.append(addPrefix(s)); @@ -468,6 +486,16 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { 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() { return cache; } @@ -941,6 +969,10 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { return Messages.LDAPSecurityRealm_DisplayName(); } + public IdStrategy getDefaultIdStrategy() { + return IdStrategy.CASE_INSENSITIVE; + } + // note that this works better in 1.528+ (JENKINS-19124) public FormValidation doCheckServer(@QueryParameter String value, @QueryParameter String managerDN, @QueryParameter Secret managerPasswordSecret) { String server = value; diff --git a/src/main/resources/hudson/security/LDAPSecurityRealm/config.jelly b/src/main/resources/hudson/security/LDAPSecurityRealm/config.jelly index f3fdd23..2f99c9e 100644 --- a/src/main/resources/hudson/security/LDAPSecurityRealm/config.jelly +++ b/src/main/resources/hudson/security/LDAPSecurityRealm/config.jelly @@ -40,6 +40,10 @@ THE SOFTWARE. + + + + diff --git a/src/main/resources/hudson/security/LDAPSecurityRealm/help-groupIdStrategy.html b/src/main/resources/hudson/security/LDAPSecurityRealm/help-groupIdStrategy.html new file mode 100644 index 0000000..e585984 --- /dev/null +++ b/src/main/resources/hudson/security/LDAPSecurityRealm/help-groupIdStrategy.html @@ -0,0 +1,18 @@ +
+ Almost all LDAP schemas use an attribute (cn) 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 Case insensitive. +

+ Recommendations: +

+
    +
  • + If your group search filter is blank or contains cn={0} then select + Case insensitive. +
  • +
  • + Otherwise consult the LDAP schema of your LDAP server to determine the correct selection, with + Case insensitive being the best choice for the lazy. +
  • +
+
\ No newline at end of file diff --git a/src/main/resources/hudson/security/LDAPSecurityRealm/help-userIdStrategy.html b/src/main/resources/hudson/security/LDAPSecurityRealm/help-userIdStrategy.html new file mode 100644 index 0000000..d2e953d --- /dev/null +++ b/src/main/resources/hudson/security/LDAPSecurityRealm/help-userIdStrategy.html @@ -0,0 +1,56 @@ +
+ Almost all LDAP schemas use an attribute (uid or mail) 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 Case insensitive. +

+ Recommendations: +

+
    +
  • If your user search filter is uid={0} then select Case insensitive.
  • +
  • If your user search filter is mail={0} then select Case insensitive.
  • +
  • + Otherwise consult the LDAP schema of your LDAP server to determine the correct selection, with + Case insensitive being the best choice for the lazy. +
  • +
+

+ Note: +

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. + RFC 2821 Section 2.4 specifies: +
+ 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. +
+ This is in conflict with the case sensitivity rules for the standard LDAP attribute used to hold email addresses + (mail) which specifies caseIgnoreIA5Match, e.g. as noted in + RFC 2798 +
+
( 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} )
+         
+ Note: RFC 1274 uses the longer name + 'rfc822Mailbox' and syntax OID of 0.9.2342.19200300.100.3.5. All recent LDAP documents + and most + deployed LDAP implementations refer to this attribute as 'mail' + and define the IA5 String syntax using using the OID + 1.3.6.1.4.1.1466.115.121.1.26, as is done here. +
+ So when the user search filter is mail={0} it is pointless to select anything other than + Case insensitive as the LDAP server will be ignoring case when searching anyway. +
+ If you do need to select a case sensitive strategy because you are searching on a custom attribute you should note + that the Case sensitive (email address) + strategy applies RFC 2821's rules on case sensitivity (i.e. the + local-part is case sensitive and the mailbox domain is case insensitive), thus with that strategy + JOE@ACME.COM and JOE@acme.com will be considered the same Jenkins user + while joe@acme.com will be considered as a different Jenkins user. +
+

+

+ Note: UNIX login names are case sensitive +

+
\ No newline at end of file