Skip to content

Commit c84b209

Browse files
committed
Remove use of BeanBuilder; construct components in Java
1 parent 7331226 commit c84b209

File tree

7 files changed

+81
-376
lines changed

7 files changed

+81
-376
lines changed

src/main/java/hudson/security/LDAPSecurityRealm.java

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@
8282
import org.kohsuke.stapler.StaplerRequest;
8383
import org.kohsuke.stapler.interceptor.RequirePOST;
8484
import org.springframework.dao.DataAccessException;
85-
import org.springframework.web.context.WebApplicationContext;
8685

8786
import javax.annotation.CheckForNull;
8887
import javax.annotation.Nonnull;
@@ -754,19 +753,19 @@ public SecurityComponents createSecurityComponents() {
754753
DelegateLDAPUserDetailsService details = new DelegateLDAPUserDetailsService();
755754
LDAPAuthenticationManager manager = new LDAPAuthenticationManager(details);
756755
for (LDAPConfiguration conf : configurations) {
757-
WebApplicationContext appContext = conf.createApplicationContext(this, false);
758-
manager.addDelegate(findBean(AuthenticationManager.class, appContext), conf.getId());
759-
details.addDelegate(new LDAPUserDetailsService(appContext, conf.getGroupMembershipStrategy(), conf.getId()));
756+
LDAPConfiguration.ApplicationContext appContext = conf.createApplicationContext(this);
757+
manager.addDelegate(appContext.authenticationManager, conf.getId());
758+
details.addDelegate(new LDAPUserDetailsService(appContext.ldapUserSearch, appContext.ldapAuthoritiesPopulator, conf.getGroupMembershipStrategy(), conf.getId()));
760759
}
761760
return new SecurityComponents(manager, details);
762761
} else {
763762
final LDAPConfiguration conf = configurations.get(0);
764-
WebApplicationContext appContext = conf.createApplicationContext(this, true);
763+
LDAPConfiguration.ApplicationContext appContext = conf.createApplicationContext(this);
765764
final LDAPAuthenticationManager manager = new LDAPAuthenticationManager();
766-
manager.addDelegate(findBean(AuthenticationManager.class, appContext), "");
765+
manager.addDelegate(appContext.authenticationManager, "");
767766
return new SecurityComponents(
768767
manager,
769-
new LDAPUserDetailsService(appContext, conf.getGroupMembershipStrategy(), null)
768+
new LDAPUserDetailsService(appContext.ldapUserSearch, appContext.ldapAuthoritiesPopulator, conf.getGroupMembershipStrategy(), null)
770769
);
771770
}
772771
}
@@ -1283,11 +1282,6 @@ public static class LDAPUserDetailsService implements UserDetailsService {
12831282
*/
12841283
private final LRUMap attributesCache = new LRUMap(32);
12851284

1286-
@Deprecated
1287-
LDAPUserDetailsService(WebApplicationContext appContext) {
1288-
this(appContext, null, null);
1289-
}
1290-
12911285
@Deprecated
12921286
LDAPUserDetailsService(LdapUserSearch ldapSearch, LdapAuthoritiesPopulator authoritiesPopulator) {
12931287
this(ldapSearch, authoritiesPopulator, null, null);
@@ -1300,17 +1294,6 @@ public static class LDAPUserDetailsService implements UserDetailsService {
13001294
this.configurationId = configurationId;
13011295
}
13021296

1303-
@Deprecated
1304-
public LDAPUserDetailsService(WebApplicationContext appContext,
1305-
LDAPGroupMembershipStrategy groupMembershipStrategy) {
1306-
this(findBean(LdapUserSearch.class, appContext), findBean(LdapAuthoritiesPopulator.class, appContext), groupMembershipStrategy, null);
1307-
}
1308-
1309-
public LDAPUserDetailsService(WebApplicationContext appContext,
1310-
LDAPGroupMembershipStrategy groupMembershipStrategy, String configurationId) {
1311-
this(findBean(LdapUserSearch.class, appContext), findBean(LdapAuthoritiesPopulator.class, appContext), groupMembershipStrategy, configurationId);
1312-
}
1313-
13141297
@SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", justification = "Only on newer core versions") //TODO remove when core is bumped
13151298
public LdapUserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
13161299
username = fixUsername(username);
@@ -1598,10 +1581,6 @@ public SecurityRealm newInstance(StaplerRequest req, JSONObject formData) throws
15981581
return super.newInstance(req, formData);
15991582
}
16001583

1601-
public boolean hasCustomBindScript() {
1602-
return LDAPConfiguration.getLdapBindOverrideFile(Jenkins.getActiveInstance()).exists();
1603-
}
1604-
16051584
/**
16061585
* Used by config.jelly to determine whether we are running on a Jenkins with Enable Security checkbox or not.
16071586
* It impacts the json structure to send when checking the ldap configuration in the filter attribute of the

src/main/java/jenkins/security/plugins/ldap/LDAPConfiguration.java

Lines changed: 69 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -26,33 +26,34 @@
2626
package jenkins.security.plugins.ldap;
2727

2828
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
29-
import groovy.lang.Binding;
3029
import hudson.DescriptorExtensionList;
3130
import hudson.Extension;
3231
import hudson.Util;
3332
import hudson.model.AbstractDescribableImpl;
3433
import hudson.model.Descriptor;
3534
import hudson.security.LDAPSecurityRealm;
36-
import hudson.security.SecurityRealm;
3735
import hudson.util.FormValidation;
3836
import hudson.util.Secret;
39-
import hudson.util.spring.BeanBuilder;
4037
import jenkins.model.Jenkins;
41-
import org.acegisecurity.ldap.InitialDirContextFactory;
42-
import org.acegisecurity.ldap.LdapTemplate;
38+
import org.acegisecurity.AuthenticationManager;
39+
import org.acegisecurity.ldap.DefaultInitialDirContextFactory;
40+
import org.acegisecurity.ldap.LdapUserSearch;
4341
import org.acegisecurity.ldap.search.FilterBasedLdapUserSearch;
42+
import org.acegisecurity.providers.AuthenticationProvider;
43+
import org.acegisecurity.providers.ProviderManager;
44+
import org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider;
4445
import org.acegisecurity.providers.ldap.LdapAuthoritiesPopulator;
46+
import org.acegisecurity.providers.ldap.authenticator.BindAuthenticator2;
47+
import org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider;
4548
import org.apache.commons.codec.Charsets;
4649
import org.apache.commons.codec.binary.Base64;
4750
import org.apache.commons.codec.digest.DigestUtils;
48-
import org.apache.commons.io.input.AutoCloseInputStream;
4951
import org.apache.commons.lang.StringUtils;
5052
import org.kohsuke.accmod.Restricted;
5153
import org.kohsuke.accmod.restrictions.NoExternalUse;
5254
import org.kohsuke.stapler.DataBoundConstructor;
5355
import org.kohsuke.stapler.DataBoundSetter;
5456
import org.kohsuke.stapler.QueryParameter;
55-
import org.springframework.web.context.WebApplicationContext;
5657

5758
import javax.annotation.Nonnull;
5859
import javax.naming.Context;
@@ -62,9 +63,6 @@
6263
import javax.naming.directory.DirContext;
6364
import javax.naming.directory.InitialDirContext;
6465

65-
import java.io.File;
66-
import java.io.FileInputStream;
67-
import java.io.FileNotFoundException;
6866
import java.io.IOException;
6967
import java.net.InetAddress;
7068
import java.net.Socket;
@@ -76,6 +74,7 @@
7674
import java.util.Arrays;
7775
import java.util.Collections;
7876
import java.util.Hashtable;
77+
import java.util.HashMap;
7978
import java.util.List;
8079
import java.util.Map;
8180
import java.util.logging.Level;
@@ -95,8 +94,6 @@
9594
public class LDAPConfiguration extends AbstractDescribableImpl<LDAPConfiguration> {
9695

9796
private static final Logger LOGGER = LDAPSecurityRealm.LOGGER;
98-
@Restricted(NoExternalUse.class)
99-
public static final String SECURITY_REALM_LDAPBIND_GROOVY = "LDAPBindSecurityRealm.groovy";
10097

10198
/**
10299
* LDAP server name(s) separated by spaces, optionally with TCP port number, like "ldap.acme.org"
@@ -400,10 +397,6 @@ public String getDisplayName() {
400397
return "ldap";
401398
}
402399

403-
public boolean noCustomBindScript() {
404-
return !getLdapBindOverrideFile(Jenkins.getActiveInstance()).exists();
405-
}
406-
407400
// note that this works better in 1.528+ (JENKINS-19124)
408401
@SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", justification = "Only on newer core versions") //TODO remove when core is bumped
409402
public FormValidation doCheckServer(@QueryParameter String value, @QueryParameter String managerDN, @QueryParameter Secret managerPasswordSecret) {
@@ -572,50 +565,80 @@ static String normalizeServer(String server) { /*package scope for testing*/
572565
return StringUtils.join(normalised, ' ');
573566
}
574567

575-
@Restricted(NoExternalUse.class)
576-
public WebApplicationContext createApplicationContext(LDAPSecurityRealm realm, boolean usePotentialUserProvidedBinding) {
577-
Binding binding = new Binding();
578-
binding.setVariable("instance", this);
579-
binding.setVariable("realmInstance", realm);
580-
581-
final Jenkins jenkins = Jenkins.getInstance();
582-
if (jenkins == null) {
583-
throw new IllegalStateException("Jenkins has not been started, or was already shut down");
568+
public static final class ApplicationContext {
569+
public final AuthenticationManager authenticationManager;
570+
public final LdapUserSearch ldapUserSearch;
571+
public final LdapAuthoritiesPopulator ldapAuthoritiesPopulator;
572+
ApplicationContext(AuthenticationManager authenticationManager, LdapUserSearch ldapUserSearch, LdapAuthoritiesPopulator ldapAuthoritiesPopulator) {
573+
this.authenticationManager = authenticationManager;
574+
this.ldapUserSearch = ldapUserSearch;
575+
this.ldapAuthoritiesPopulator = ldapAuthoritiesPopulator;
584576
}
577+
}
585578

586-
BeanBuilder builder = new BeanBuilder(jenkins.pluginManager.uberClassLoader);
587-
try {
588-
File override = getLdapBindOverrideFile(jenkins);
589-
if (usePotentialUserProvidedBinding && override.exists()) {
590-
builder.parse(new AutoCloseInputStream(new FileInputStream(override)), binding);
591-
} else {
592-
if (override.exists()) {
593-
LOGGER.warning("Not loading custom " + SECURITY_REALM_LDAPBIND_GROOVY);
594-
}
595-
builder.parse(new AutoCloseInputStream(LDAPSecurityRealm.class.getResourceAsStream(SECURITY_REALM_LDAPBIND_GROOVY)), binding);
596-
}
579+
@Restricted(NoExternalUse.class)
580+
public ApplicationContext createApplicationContext(LDAPSecurityRealm realm) {
581+
DefaultInitialDirContextFactory initialDirContextFactory = new DefaultInitialDirContextFactory(getLDAPURL());
582+
if (getManagerDN() != null) {
583+
initialDirContextFactory.setManagerDn(getManagerDN());
584+
initialDirContextFactory.setManagerPassword(getManagerPassword());
585+
}
586+
Map<String, String> vars = new HashMap<>();
587+
vars.put(Context.REFERRAL, "follow");
588+
vars.put("com.sun.jndi.ldap.connect.timeout", "30000"); // timeout if no connection after 30 seconds
589+
vars.put("com.sun.jndi.ldap.read.timeout", "60000"); // timeout if no response after 60 seconds
590+
vars.putAll(getExtraEnvVars());
591+
initialDirContextFactory.setExtraEnvVars(vars);
592+
593+
FilterBasedLdapUserSearch ldapUserSearch = new FilterBasedLdapUserSearch(getUserSearchBase(), getUserSearch(), initialDirContextFactory);
594+
ldapUserSearch.setSearchSubtree(true);
595+
596+
BindAuthenticator2 bindAuthenticator = new BindAuthenticator2(initialDirContextFactory);
597+
// this is when you the user name can be translated into DN.
598+
// bindAuthenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
599+
// this is when we need to find it.
600+
bindAuthenticator.setUserSearch(ldapUserSearch);
601+
602+
LDAPSecurityRealm.AuthoritiesPopulatorImpl ldapAuthoritiesPopulator = new LDAPSecurityRealm.AuthoritiesPopulatorImpl(initialDirContextFactory, getGroupSearchBase());
603+
ldapAuthoritiesPopulator.setSearchSubtree(true);
604+
ldapAuthoritiesPopulator.setGroupSearchFilter("(| (member={0}) (uniqueMember={0}) (memberUid={1}))");
605+
if (realm.isDisableRolePrefixing()) {
606+
ldapAuthoritiesPopulator.setRolePrefix("");
607+
ldapAuthoritiesPopulator.setConvertToUpperCase(false);
608+
}
597609

598-
} catch (FileNotFoundException e) {
599-
throw new IllegalStateException("Failed to load "+ SECURITY_REALM_LDAPBIND_GROOVY, e);
610+
ProviderManager authenticationManager = new ProviderManager();
611+
List<AuthenticationProvider> providers = new ArrayList<>();
612+
// talk to LDAP
613+
providers.add(new LDAPSecurityRealm.LdapAuthenticationProviderImpl(bindAuthenticator, ldapAuthoritiesPopulator, getGroupMembershipStrategy()));
614+
// these providers apply everywhere
615+
{
616+
RememberMeAuthenticationProvider rememberMeAuthenticationProvider = new RememberMeAuthenticationProvider();
617+
rememberMeAuthenticationProvider.setKey(Jenkins.getInstance().getSecretKey());
618+
providers.add(rememberMeAuthenticationProvider);
600619
}
601-
WebApplicationContext appContext = builder.createApplicationContext();
620+
{
621+
// this doesn't mean we allow anonymous access.
622+
// we just authenticate anonymous users as such,
623+
// so that later authorization can reject them if so configured
624+
AnonymousAuthenticationProvider anonymousAuthenticationProvider = new AnonymousAuthenticationProvider();
625+
anonymousAuthenticationProvider.setKey("anonymous");
626+
providers.add(anonymousAuthenticationProvider);
627+
}
628+
authenticationManager.setProviders(providers);
602629

603-
ldapTemplate = new LDAPExtendedTemplate(SecurityRealm.findBean(InitialDirContextFactory.class, appContext));
630+
ldapTemplate = new LDAPExtendedTemplate(initialDirContextFactory);
604631

605632
if (groupMembershipStrategy != null) {
606-
groupMembershipStrategy.setAuthoritiesPopulator(SecurityRealm.findBean(LdapAuthoritiesPopulator.class, appContext));
633+
groupMembershipStrategy.setAuthoritiesPopulator(ldapAuthoritiesPopulator);
607634
}
608635

609-
return appContext;
636+
return new ApplicationContext(authenticationManager, ldapUserSearch, ldapAuthoritiesPopulator);
610637
}
611638

612639
@Restricted(NoExternalUse.class)
613640
public LDAPExtendedTemplate getLdapTemplate() {
614641
return ldapTemplate;
615642
}
616643

617-
@Restricted(NoExternalUse.class)
618-
public static File getLdapBindOverrideFile(Jenkins jenkins) {
619-
return new File(jenkins.getRootDir(), SECURITY_REALM_LDAPBIND_GROOVY);
620-
}
621644
}

src/main/resources/hudson/security/LDAPBindSecurityRealm.groovy

Lines changed: 0 additions & 93 deletions
This file was deleted.

src/main/resources/hudson/security/LDAPSecurityRealm/config.jelly

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,15 @@ THE SOFTWARE.
2525
<?jelly escape-by-default='true'?>
2626
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:st="jelly:stapler" xmlns:l="/lib/layout"
2727
xmlns:v="/jenkins/security/plugins/ldap/validation">
28-
<j:if test="${descriptor.hasCustomBindScript()}">
29-
<f:description>
30-
<j:out value="${%customBindingBlurb}"/>
31-
</f:description>
32-
</j:if>
3328
<f:entry>
34-
<f:repeatable field="configurations" minimum="1" header="${%Server}" add="${%Add Server}" noAddButton="${descriptor.hasCustomBindScript()}">
29+
<f:repeatable field="configurations" minimum="1" header="${%Server}" add="${%Add Server}">
3530
<table style="width:100%">
3631
<st:include page="config.jelly" class="jenkins.security.plugins.ldap.LDAPConfiguration"/>
37-
<j:if test="${descriptor.noCustomBindScript()}">
38-
<f:entry title="">
39-
<div align="right">
40-
<f:repeatableDeleteButton/>
41-
</div>
42-
</f:entry>
43-
</j:if>
32+
<f:entry title="">
33+
<div align="right">
34+
<f:repeatableDeleteButton/>
35+
</div>
36+
</f:entry>
4437
</table>
4538
</f:repeatable>
4639
</f:entry>

src/main/resources/hudson/security/LDAPSecurityRealm/config.properties

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,3 @@ validationBlurb=<p>Use your LDAP username and password to test your LDAP setting
44
password if you don't know their password to validate that user lookup is working.</p>\
55
<p>If you are using LDAP groups, test a user account that is a member of at least one LDAP \
66
group to validate reverse group lookup.</p>
7-
customBindingBlurb=<p>Ability to make multiple server configurations turned off due to the presence of custom <em>LDAPBindSecurityRealm.groovy<em></p>

0 commit comments

Comments
 (0)