Skip to content

Commit

Permalink
[FIXED JENKINS-18355] LDAP does not populate Your Name field
Browse files Browse the repository at this point in the history
Towards 1.8
  • Loading branch information
stephenc committed Jan 17, 2014
1 parent f19e369 commit 631a3f0
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 7 deletions.
96 changes: 89 additions & 7 deletions src/main/java/hudson/security/LDAPSecurityRealm.java
Expand Up @@ -32,12 +32,14 @@

import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
import hudson.tasks.Mailer;
import jenkins.model.Jenkins;
import hudson.model.User;
import hudson.tasks.MailAddressResolver;
import hudson.util.FormValidation;
import hudson.util.Scrambler;
import hudson.util.spring.BeanBuilder;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.AcegiSecurityException;
Expand All @@ -58,6 +60,7 @@
import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
import org.apache.commons.collections.map.LRUMap;
import org.apache.commons.io.input.AutoCloseInputStream;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.springframework.dao.DataAccessException;
Expand Down Expand Up @@ -221,6 +224,8 @@
* @since 1.166
*/
public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
private static final String DEFAULT_DISPLAYNAME_ATTRIBUTE_NAME = "displayname";
private static final String DEFAULT_MAILADDRESS_ATTRIBUTE_NAME = "mail";
/**
* LDAP server name(s) separated by spaces, optionally with TCP port number, like "ldap.acme.org"
* or "ldap.acme.org:389" and/or with protcol, like "ldap://ldap.acme.org".
Expand Down Expand Up @@ -338,6 +343,10 @@ group target (CN is a reasonable default)

private final Map<String,String> extraEnvVars;

private final String displayNameAttributeName;

private final String mailAddressAttributeName;

/**
* @deprecated retained for backwards binary compatibility.
*/
Expand Down Expand Up @@ -373,8 +382,16 @@ public LDAPSecurityRealm(String server, String rootDN, String userSearchBase, St
this(server, rootDN, userSearchBase, userSearch, groupSearchBase, groupSearchFilter, groupMembershipFilter, managerDN, managerPassword, inhibitInferRootDN, disableMailAddressResolver, cache, null);
}

@DataBoundConstructor
/**
* @deprecated retained for backwards binary compatibility.
*/
@Deprecated
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, EnvironmentProperty[] environmentProperties) {
this(server, rootDN, userSearchBase, userSearch, groupSearchBase, groupSearchFilter, groupMembershipFilter, managerDN, managerPassword, inhibitInferRootDN, disableMailAddressResolver, cache, environmentProperties, null, null);
}

@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, EnvironmentProperty[] environmentProperties, String displayNameAttributeName, String mailAddressAttributeName) {
this.server = server.trim();
this.managerDN = fixEmpty(managerDN);
this.managerPassword = Scrambler.scramble(fixEmpty(managerPassword));
Expand All @@ -392,6 +409,10 @@ public LDAPSecurityRealm(String server, String rootDN, String userSearchBase, St
this.extraEnvVars = environmentProperties == null || environmentProperties.length == 0
? null
: EnvironmentProperty.toMap(Arrays.asList(environmentProperties));
this.displayNameAttributeName = StringUtils.defaultString(fixEmptyAndTrim(displayNameAttributeName),
DEFAULT_DISPLAYNAME_ATTRIBUTE_NAME);
this.mailAddressAttributeName = StringUtils.defaultString(fixEmptyAndTrim(mailAddressAttributeName),
DEFAULT_MAILADDRESS_ATTRIBUTE_NAME);
}

public String getServerUrl() {
Expand Down Expand Up @@ -498,6 +519,14 @@ public String getLDAPURL() {
return toProviderUrl(getServerUrl(), fixNull(rootDN));
}

public String getDisplayNameAttributeName() {
return StringUtils.defaultString(displayNameAttributeName, DEFAULT_DISPLAYNAME_ATTRIBUTE_NAME);
}

public String getMailAddressAttributeName() {
return StringUtils.defaultString(mailAddressAttributeName, DEFAULT_MAILADDRESS_ATTRIBUTE_NAME);
}

public SecurityComponents createSecurityComponents() {
Binding binding = new Binding();
binding.setVariable("instance", this);
Expand All @@ -522,7 +551,7 @@ public SecurityComponents createSecurityComponents() {
}

return new SecurityComponents(
findBean(AuthenticationManager.class, appContext),
new LDAPAuthenticationManager(findBean(AuthenticationManager.class, appContext)),
new LDAPUserDetailsService(appContext));
}

Expand All @@ -531,16 +560,55 @@ public SecurityComponents createSecurityComponents() {
*/
@Override
protected UserDetails authenticate(String username, String password) throws AuthenticationException {
return (UserDetails) getSecurityComponents().manager.authenticate(
new UsernamePasswordAuthenticationToken(username, password)).getPrincipal();
return updateUserDetails((UserDetails) getSecurityComponents().manager.authenticate(
new UsernamePasswordAuthenticationToken(username, password)).getPrincipal());
}

/**
* {@inheritDoc}
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
return getSecurityComponents().userDetails.loadUserByUsername(username);
return updateUserDetails(getSecurityComponents().userDetails.loadUserByUsername(username));
}

public Authentication updateUserDetails(Authentication authentication) {
updateUserDetails((UserDetails) authentication.getPrincipal());
return authentication;
}

public UserDetails updateUserDetails(UserDetails userDetails) {
if (userDetails instanceof LdapUserDetails) {
updateUserDetails((LdapUserDetails)userDetails);
}
return userDetails;
}

public LdapUserDetails updateUserDetails(LdapUserDetails d) {
hudson.model.User u = hudson.model.User.get(d.getUsername());
try {
Attribute attribute = d.getAttributes().get(getDisplayNameAttributeName());
String displayName = attribute == null ? null : (String) attribute.get();
if (StringUtils.isNotBlank(displayName) && u.getId().equals(u.getFullName())) {
u.setFullName(displayName);
}
} catch (NamingException e) {
LOGGER.log(Level.FINEST, "Could not retrieve display name attribute", e);
}
if (!disableMailAddressResolver) {
try {
Attribute attribute = d.getAttributes().get(getMailAddressAttributeName());
String mailAddress = attribute == null ? null : (String) attribute.get();
if (StringUtils.isNotBlank(mailAddress)) {
u.addProperty(new Mailer.UserProperty(mailAddress));
}
} catch (NamingException e) {
LOGGER.log(Level.FINEST, "Could not retrieve email address attribute", e);
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Failed to associate the e-mail address", e);
}
}
return d;
}

@Override
Expand Down Expand Up @@ -586,6 +654,19 @@ public String getName() {
};
}

private class LDAPAuthenticationManager implements AuthenticationManager {

private final AuthenticationManager delegate;

private LDAPAuthenticationManager(AuthenticationManager delegate) {
this.delegate = delegate;
}

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return updateUserDetails(delegate.authenticate(authentication));
}
}

public static class LDAPUserDetailsService implements UserDetailsService {
public final LdapUserSearch ldapSearch;
public final LdapAuthoritiesPopulator authoritiesPopulator;
Expand Down Expand Up @@ -656,7 +737,8 @@ public LdapUserDetails loadUserByUsername(String username) throws UsernameNotFou
new CacheMap<String, LdapUserDetails>(ldapSecurityRealm.cache.getSize());
}
ldapSecurityRealm.userDetailsCache.put(username,
new CacheEntry<LdapUserDetails>(ldapSecurityRealm.cache.getTtl(), ldapUser));
new CacheEntry<LdapUserDetails>(ldapSecurityRealm.cache.getTtl(),
ldapSecurityRealm.updateUserDetails(ldapUser)));
}
}
}
Expand Down Expand Up @@ -685,7 +767,7 @@ public String findMailAddressFor(User u) {
}
try {
LdapUserDetails details = (LdapUserDetails)realm.getSecurityComponents().userDetails.loadUserByUsername(u.getId());
Attribute mail = details.getAttributes().get("mail");
Attribute mail = details.getAttributes().get(((LDAPSecurityRealm)realm).getMailAddressAttributeName());
if(mail==null) return null; // not found
return (String)mail.get();
} catch (UsernameNotFoundException e) {
Expand Down
Expand Up @@ -59,6 +59,12 @@ THE SOFTWARE.
checkUrl="'${rootURL}/securityRealms/LDAPSecurityRealm/serverCheck?field=password&amp;server='+encodeURIComponent(this.form.elements['ldap.server'].value)+'&amp;managerDN='+encodeURIComponent(this.form.elements['ldap.managerDN'].value)+'&amp;managerPassword='+encodeURIComponent(this.value)"
/>
</f:entry>
<f:entry title="${%Display Name LDAP attribute}" help="/plugin/ldap/help-displayNameAttributeName.html">
<f:textbox name="ldap.displayNameAttributeName" value="${instance.displayNameAttributeName}"/>
</f:entry>
<f:entry title="${%Email Address LDAP attribute}" help="/plugin/ldap/help-mailAddressAttributeName.html">
<f:textbox name="ldap.mailAddressAttributeName" value="${instance.mailAddressAttributeName}"/>
</f:entry>
<f:entry title="${%Disable Ldap Email Resolver}">
<f:checkbox name="ldap.disableMailAddressResolver" checked="${instance.disableMailAddressResolver}"></f:checkbox>
</f:entry>
Expand Down
4 changes: 4 additions & 0 deletions src/main/webapp/help-displayNameAttributeName.html
@@ -0,0 +1,4 @@
<div>
When a user's details are resolved from LDAP, the specified attribute in those user details will be consulted
to retrieve the display name for the user.
</div>
4 changes: 4 additions & 0 deletions src/main/webapp/help-mailAddressAttributeName.html
@@ -0,0 +1,4 @@
<div>
When a user's details are resolved from LDAP, the specified attribute in those user details will be consulted
to retrieve the email address for the user unless the email address resolver is disabled.
</div>

0 comments on commit 631a3f0

Please sign in to comment.